[media] move i2c files into drivers/media/i2c
Move ancillary I2C drivers into drivers/media/i2c, in order to better organize them. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
f0af8fa4da
commit
cb7a01ac32
124 changed files with 671 additions and 689 deletions
|
|
@ -151,18 +151,15 @@ source "drivers/media/rc/Kconfig"
|
|||
|
||||
source "drivers/media/tuners/Kconfig"
|
||||
|
||||
#
|
||||
# Video/Radio/Hybrid adapters
|
||||
#
|
||||
source "drivers/media/i2c/Kconfig"
|
||||
|
||||
#
|
||||
# V4L platform/mem2mem drivers
|
||||
#
|
||||
source "drivers/media/video/Kconfig"
|
||||
|
||||
source "drivers/media/radio/Kconfig"
|
||||
|
||||
#
|
||||
# DVB adapters
|
||||
#
|
||||
|
||||
source "drivers/media/pci/Kconfig"
|
||||
source "drivers/media/usb/Kconfig"
|
||||
source "drivers/media/mmc/Kconfig"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
|
|||
endif
|
||||
|
||||
obj-y += tuners/ common/ rc/ video/
|
||||
obj-y += pci/ usb/ mmc/ firewire/ parport/
|
||||
obj-y += i2c/ pci/ usb/ mmc/ firewire/ parport/
|
||||
|
||||
obj-$(CONFIG_VIDEO_DEV) += radio/ v4l2-core/
|
||||
obj-$(CONFIG_DVB_CORE) += dvb-core/ dvb-frontends/
|
||||
|
|
|
|||
566
drivers/media/i2c/Kconfig
Normal file
566
drivers/media/i2c/Kconfig
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
#
|
||||
# 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_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/i2c/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/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
|
||||
endif
|
||||
63
drivers/media/i2c/Makefile
Normal file
63
drivers/media/i2c/Makefile
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
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-$(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
|
||||
487
drivers/media/i2c/adp1653.c
Normal file
487
drivers/media/i2c/adp1653.c
Normal file
|
|
@ -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");
|
||||
410
drivers/media/i2c/adv7170.c
Normal file
410
drivers/media/i2c/adv7170.c
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
/*
|
||||
* adv7170 - adv7170, adv7171 video encoder driver version 0.0.1
|
||||
*
|
||||
* Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com>
|
||||
*
|
||||
* Based on adv7176 driver by:
|
||||
*
|
||||
* Copyright (C) 1998 Dave Perks <dperks@ibm.net>
|
||||
* Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
|
||||
* Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
|
||||
* - some corrections for Pinnacle Systems Inc. DC10plus card.
|
||||
*
|
||||
* Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
* - moved over to linux>=2.4.x i2c protocol (1/1/2003)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the 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/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
|
||||
MODULE_AUTHOR("Maxim Yevtyushkin");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
struct adv7170 {
|
||||
struct v4l2_subdev sd;
|
||||
unsigned char reg[128];
|
||||
|
||||
v4l2_std_id norm;
|
||||
int input;
|
||||
};
|
||||
|
||||
static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct adv7170, sd);
|
||||
}
|
||||
|
||||
static char *inputs[] = { "pass_through", "play_back" };
|
||||
|
||||
static enum v4l2_mbus_pixelcode adv7170_codes[] = {
|
||||
V4L2_MBUS_FMT_UYVY8_2X8,
|
||||
V4L2_MBUS_FMT_UYVY8_1X16,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct adv7170 *encoder = to_adv7170(sd);
|
||||
|
||||
encoder->reg[reg] = value;
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline int adv7170_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 adv7170_write_block(struct v4l2_subdev *sd,
|
||||
const u8 *data, unsigned int len)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct adv7170 *encoder = to_adv7170(sd);
|
||||
int ret = -1;
|
||||
u8 reg;
|
||||
|
||||
/* the adv7170 has an autoincrement function, use it if
|
||||
* the adapter understands raw I2C */
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
/* do raw I2C, not smbus compatible */
|
||||
u8 block_data[32];
|
||||
int block_len;
|
||||
|
||||
while (len >= 2) {
|
||||
block_len = 0;
|
||||
block_data[block_len++] = reg = data[0];
|
||||
do {
|
||||
block_data[block_len++] =
|
||||
encoder->reg[reg++] = data[1];
|
||||
len -= 2;
|
||||
data += 2;
|
||||
} while (len >= 2 && data[0] == reg && block_len < 32);
|
||||
ret = i2c_master_send(client, block_data, block_len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* do some slow I2C emulation kind of thing */
|
||||
while (len >= 2) {
|
||||
reg = *data++;
|
||||
ret = adv7170_write(sd, reg, *data++);
|
||||
if (ret < 0)
|
||||
break;
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
#define TR0MODE 0x4c
|
||||
#define TR0RST 0x80
|
||||
|
||||
#define TR1CAPT 0x00
|
||||
#define TR1PLAY 0x00
|
||||
|
||||
static const unsigned char init_NTSC[] = {
|
||||
0x00, 0x10, /* MR0 */
|
||||
0x01, 0x20, /* MR1 */
|
||||
0x02, 0x0e, /* MR2 RTC control: bits 2 and 1 */
|
||||
0x03, 0x80, /* MR3 */
|
||||
0x04, 0x30, /* MR4 */
|
||||
0x05, 0x00, /* Reserved */
|
||||
0x06, 0x00, /* Reserved */
|
||||
0x07, TR0MODE, /* TM0 */
|
||||
0x08, TR1CAPT, /* TM1 */
|
||||
0x09, 0x16, /* Fsc0 */
|
||||
0x0a, 0x7c, /* Fsc1 */
|
||||
0x0b, 0xf0, /* Fsc2 */
|
||||
0x0c, 0x21, /* Fsc3 */
|
||||
0x0d, 0x00, /* Subcarrier Phase */
|
||||
0x0e, 0x00, /* Closed Capt. Ext 0 */
|
||||
0x0f, 0x00, /* Closed Capt. Ext 1 */
|
||||
0x10, 0x00, /* Closed Capt. 0 */
|
||||
0x11, 0x00, /* Closed Capt. 1 */
|
||||
0x12, 0x00, /* Pedestal Ctl 0 */
|
||||
0x13, 0x00, /* Pedestal Ctl 1 */
|
||||
0x14, 0x00, /* Pedestal Ctl 2 */
|
||||
0x15, 0x00, /* Pedestal Ctl 3 */
|
||||
0x16, 0x00, /* CGMS_WSS_0 */
|
||||
0x17, 0x00, /* CGMS_WSS_1 */
|
||||
0x18, 0x00, /* CGMS_WSS_2 */
|
||||
0x19, 0x00, /* Teletext Ctl */
|
||||
};
|
||||
|
||||
static const unsigned char init_PAL[] = {
|
||||
0x00, 0x71, /* MR0 */
|
||||
0x01, 0x20, /* MR1 */
|
||||
0x02, 0x0e, /* MR2 RTC control: bits 2 and 1 */
|
||||
0x03, 0x80, /* MR3 */
|
||||
0x04, 0x30, /* MR4 */
|
||||
0x05, 0x00, /* Reserved */
|
||||
0x06, 0x00, /* Reserved */
|
||||
0x07, TR0MODE, /* TM0 */
|
||||
0x08, TR1CAPT, /* TM1 */
|
||||
0x09, 0xcb, /* Fsc0 */
|
||||
0x0a, 0x8a, /* Fsc1 */
|
||||
0x0b, 0x09, /* Fsc2 */
|
||||
0x0c, 0x2a, /* Fsc3 */
|
||||
0x0d, 0x00, /* Subcarrier Phase */
|
||||
0x0e, 0x00, /* Closed Capt. Ext 0 */
|
||||
0x0f, 0x00, /* Closed Capt. Ext 1 */
|
||||
0x10, 0x00, /* Closed Capt. 0 */
|
||||
0x11, 0x00, /* Closed Capt. 1 */
|
||||
0x12, 0x00, /* Pedestal Ctl 0 */
|
||||
0x13, 0x00, /* Pedestal Ctl 1 */
|
||||
0x14, 0x00, /* Pedestal Ctl 2 */
|
||||
0x15, 0x00, /* Pedestal Ctl 3 */
|
||||
0x16, 0x00, /* CGMS_WSS_0 */
|
||||
0x17, 0x00, /* CGMS_WSS_1 */
|
||||
0x18, 0x00, /* CGMS_WSS_2 */
|
||||
0x19, 0x00, /* Teletext Ctl */
|
||||
};
|
||||
|
||||
|
||||
static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct adv7170 *encoder = to_adv7170(sd);
|
||||
|
||||
v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
|
||||
|
||||
if (std & V4L2_STD_NTSC) {
|
||||
adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
|
||||
if (encoder->input == 0)
|
||||
adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
|
||||
adv7170_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7170_write(sd, 0x07, TR0MODE);
|
||||
} else if (std & V4L2_STD_PAL) {
|
||||
adv7170_write_block(sd, init_PAL, sizeof(init_PAL));
|
||||
if (encoder->input == 0)
|
||||
adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
|
||||
adv7170_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7170_write(sd, 0x07, TR0MODE);
|
||||
} else {
|
||||
v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
|
||||
(unsigned long long)std);
|
||||
return -EINVAL;
|
||||
}
|
||||
v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
|
||||
encoder->norm = std;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7170_s_routing(struct v4l2_subdev *sd,
|
||||
u32 input, u32 output, u32 config)
|
||||
{
|
||||
struct adv7170 *encoder = to_adv7170(sd);
|
||||
|
||||
/* RJ: input = 0: input is from decoder
|
||||
input = 1: input is from ZR36060
|
||||
input = 2: color bar */
|
||||
|
||||
v4l2_dbg(1, debug, sd, "set input from %s\n",
|
||||
input == 0 ? "decoder" : "ZR36060");
|
||||
|
||||
switch (input) {
|
||||
case 0:
|
||||
adv7170_write(sd, 0x01, 0x20);
|
||||
adv7170_write(sd, 0x08, TR1CAPT); /* TR1 */
|
||||
adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
|
||||
adv7170_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7170_write(sd, 0x07, TR0MODE);
|
||||
/* udelay(10); */
|
||||
break;
|
||||
|
||||
case 1:
|
||||
adv7170_write(sd, 0x01, 0x00);
|
||||
adv7170_write(sd, 0x08, TR1PLAY); /* TR1 */
|
||||
adv7170_write(sd, 0x02, 0x08);
|
||||
adv7170_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7170_write(sd, 0x07, TR0MODE);
|
||||
/* udelay(10); */
|
||||
break;
|
||||
|
||||
default:
|
||||
v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
|
||||
return -EINVAL;
|
||||
}
|
||||
v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
|
||||
encoder->input = input;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7170_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
|
||||
enum v4l2_mbus_pixelcode *code)
|
||||
{
|
||||
if (index >= ARRAY_SIZE(adv7170_codes))
|
||||
return -EINVAL;
|
||||
|
||||
*code = adv7170_codes[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7170_g_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *mf)
|
||||
{
|
||||
u8 val = adv7170_read(sd, 0x7);
|
||||
|
||||
if ((val & 0x40) == (1 << 6))
|
||||
mf->code = V4L2_MBUS_FMT_UYVY8_1X16;
|
||||
else
|
||||
mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
|
||||
|
||||
mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
mf->width = 0;
|
||||
mf->height = 0;
|
||||
mf->field = V4L2_FIELD_ANY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7170_s_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *mf)
|
||||
{
|
||||
u8 val = adv7170_read(sd, 0x7);
|
||||
int ret;
|
||||
|
||||
switch (mf->code) {
|
||||
case V4L2_MBUS_FMT_UYVY8_2X8:
|
||||
val &= ~0x40;
|
||||
break;
|
||||
|
||||
case V4L2_MBUS_FMT_UYVY8_1X16:
|
||||
val |= 0x40;
|
||||
break;
|
||||
|
||||
default:
|
||||
v4l2_dbg(1, debug, sd,
|
||||
"illegal v4l2_mbus_framefmt code: %d\n", mf->code);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = adv7170_write(sd, 0x7, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7170, 0);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct v4l2_subdev_core_ops adv7170_core_ops = {
|
||||
.g_chip_ident = adv7170_g_chip_ident,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops adv7170_video_ops = {
|
||||
.s_std_output = adv7170_s_std_output,
|
||||
.s_routing = adv7170_s_routing,
|
||||
.s_mbus_fmt = adv7170_s_fmt,
|
||||
.g_mbus_fmt = adv7170_g_fmt,
|
||||
.enum_mbus_fmt = adv7170_enum_fmt,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops adv7170_ops = {
|
||||
.core = &adv7170_core_ops,
|
||||
.video = &adv7170_video_ops,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int adv7170_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adv7170 *encoder;
|
||||
struct v4l2_subdev *sd;
|
||||
int i;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
|
||||
if (encoder == NULL)
|
||||
return -ENOMEM;
|
||||
sd = &encoder->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &adv7170_ops);
|
||||
encoder->norm = V4L2_STD_NTSC;
|
||||
encoder->input = 0;
|
||||
|
||||
i = adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
|
||||
if (i >= 0) {
|
||||
i = adv7170_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
i = adv7170_write(sd, 0x07, TR0MODE);
|
||||
i = adv7170_read(sd, 0x12);
|
||||
v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
|
||||
}
|
||||
if (i < 0)
|
||||
v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7170_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(to_adv7170(sd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct i2c_device_id adv7170_id[] = {
|
||||
{ "adv7170", 0 },
|
||||
{ "adv7171", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adv7170_id);
|
||||
|
||||
static struct i2c_driver adv7170_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "adv7170",
|
||||
},
|
||||
.probe = adv7170_probe,
|
||||
.remove = adv7170_remove,
|
||||
.id_table = adv7170_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(adv7170_driver);
|
||||
460
drivers/media/i2c/adv7175.c
Normal file
460
drivers/media/i2c/adv7175.c
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
/*
|
||||
* adv7175 - adv7175a video encoder driver version 0.0.3
|
||||
*
|
||||
* Copyright (C) 1998 Dave Perks <dperks@ibm.net>
|
||||
* Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net>
|
||||
* Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
|
||||
* - some corrections for Pinnacle Systems Inc. DC10plus card.
|
||||
*
|
||||
* Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
* - moved over to linux>=2.4.x i2c protocol (9/9/2002)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the 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/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
|
||||
MODULE_AUTHOR("Dave Perks");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define I2C_ADV7175 0xd4
|
||||
#define I2C_ADV7176 0x54
|
||||
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
struct adv7175 {
|
||||
struct v4l2_subdev sd;
|
||||
v4l2_std_id norm;
|
||||
int input;
|
||||
};
|
||||
|
||||
static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct adv7175, sd);
|
||||
}
|
||||
|
||||
static char *inputs[] = { "pass_through", "play_back", "color_bar" };
|
||||
|
||||
static enum v4l2_mbus_pixelcode adv7175_codes[] = {
|
||||
V4L2_MBUS_FMT_UYVY8_2X8,
|
||||
V4L2_MBUS_FMT_UYVY8_1X16,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int adv7175_write(struct v4l2_subdev *sd, u8 reg, u8 value)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline int adv7175_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 adv7175_write_block(struct v4l2_subdev *sd,
|
||||
const u8 *data, unsigned int len)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
int ret = -1;
|
||||
u8 reg;
|
||||
|
||||
/* the adv7175 has an autoincrement function, use it if
|
||||
* the adapter understands raw I2C */
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
/* do raw I2C, not smbus compatible */
|
||||
u8 block_data[32];
|
||||
int block_len;
|
||||
|
||||
while (len >= 2) {
|
||||
block_len = 0;
|
||||
block_data[block_len++] = reg = data[0];
|
||||
do {
|
||||
block_data[block_len++] = data[1];
|
||||
reg++;
|
||||
len -= 2;
|
||||
data += 2;
|
||||
} while (len >= 2 && data[0] == reg && block_len < 32);
|
||||
ret = i2c_master_send(client, block_data, block_len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* do some slow I2C emulation kind of thing */
|
||||
while (len >= 2) {
|
||||
reg = *data++;
|
||||
ret = adv7175_write(sd, reg, *data++);
|
||||
if (ret < 0)
|
||||
break;
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void set_subcarrier_freq(struct v4l2_subdev *sd, int pass_through)
|
||||
{
|
||||
/* for some reason pass_through NTSC needs
|
||||
* a different sub-carrier freq to remain stable. */
|
||||
if (pass_through)
|
||||
adv7175_write(sd, 0x02, 0x00);
|
||||
else
|
||||
adv7175_write(sd, 0x02, 0x55);
|
||||
|
||||
adv7175_write(sd, 0x03, 0x55);
|
||||
adv7175_write(sd, 0x04, 0x55);
|
||||
adv7175_write(sd, 0x05, 0x25);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* Output filter: S-Video Composite */
|
||||
|
||||
#define MR050 0x11 /* 0x09 */
|
||||
#define MR060 0x14 /* 0x0c */
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
#define TR0MODE 0x46
|
||||
#define TR0RST 0x80
|
||||
|
||||
#define TR1CAPT 0x80
|
||||
#define TR1PLAY 0x00
|
||||
|
||||
static const unsigned char init_common[] = {
|
||||
|
||||
0x00, MR050, /* MR0, PAL enabled */
|
||||
0x01, 0x00, /* MR1 */
|
||||
0x02, 0x0c, /* subc. freq. */
|
||||
0x03, 0x8c, /* subc. freq. */
|
||||
0x04, 0x79, /* subc. freq. */
|
||||
0x05, 0x26, /* subc. freq. */
|
||||
0x06, 0x40, /* subc. phase */
|
||||
|
||||
0x07, TR0MODE, /* TR0, 16bit */
|
||||
0x08, 0x21, /* */
|
||||
0x09, 0x00, /* */
|
||||
0x0a, 0x00, /* */
|
||||
0x0b, 0x00, /* */
|
||||
0x0c, TR1CAPT, /* TR1 */
|
||||
0x0d, 0x4f, /* MR2 */
|
||||
0x0e, 0x00, /* */
|
||||
0x0f, 0x00, /* */
|
||||
0x10, 0x00, /* */
|
||||
0x11, 0x00, /* */
|
||||
};
|
||||
|
||||
static const unsigned char init_pal[] = {
|
||||
0x00, MR050, /* MR0, PAL enabled */
|
||||
0x01, 0x00, /* MR1 */
|
||||
0x02, 0x0c, /* subc. freq. */
|
||||
0x03, 0x8c, /* subc. freq. */
|
||||
0x04, 0x79, /* subc. freq. */
|
||||
0x05, 0x26, /* subc. freq. */
|
||||
0x06, 0x40, /* subc. phase */
|
||||
};
|
||||
|
||||
static const unsigned char init_ntsc[] = {
|
||||
0x00, MR060, /* MR0, NTSC enabled */
|
||||
0x01, 0x00, /* MR1 */
|
||||
0x02, 0x55, /* subc. freq. */
|
||||
0x03, 0x55, /* subc. freq. */
|
||||
0x04, 0x55, /* subc. freq. */
|
||||
0x05, 0x25, /* subc. freq. */
|
||||
0x06, 0x1a, /* subc. phase */
|
||||
};
|
||||
|
||||
static int adv7175_init(struct v4l2_subdev *sd, u32 val)
|
||||
{
|
||||
/* This is just for testing!!! */
|
||||
adv7175_write_block(sd, init_common, sizeof(init_common));
|
||||
adv7175_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7175_write(sd, 0x07, TR0MODE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct adv7175 *encoder = to_adv7175(sd);
|
||||
|
||||
if (std & V4L2_STD_NTSC) {
|
||||
adv7175_write_block(sd, init_ntsc, sizeof(init_ntsc));
|
||||
if (encoder->input == 0)
|
||||
adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */
|
||||
adv7175_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7175_write(sd, 0x07, TR0MODE);
|
||||
} else if (std & V4L2_STD_PAL) {
|
||||
adv7175_write_block(sd, init_pal, sizeof(init_pal));
|
||||
if (encoder->input == 0)
|
||||
adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */
|
||||
adv7175_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7175_write(sd, 0x07, TR0MODE);
|
||||
} else if (std & V4L2_STD_SECAM) {
|
||||
/* This is an attempt to convert
|
||||
* SECAM->PAL (typically it does not work
|
||||
* due to genlock: when decoder is in SECAM
|
||||
* and encoder in in PAL the subcarrier can
|
||||
* not be syncronized with horizontal
|
||||
* quency) */
|
||||
adv7175_write_block(sd, init_pal, sizeof(init_pal));
|
||||
if (encoder->input == 0)
|
||||
adv7175_write(sd, 0x0d, 0x49); /* Disable genlock */
|
||||
adv7175_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7175_write(sd, 0x07, TR0MODE);
|
||||
} else {
|
||||
v4l2_dbg(1, debug, sd, "illegal norm: %llx\n",
|
||||
(unsigned long long)std);
|
||||
return -EINVAL;
|
||||
}
|
||||
v4l2_dbg(1, debug, sd, "switched to %llx\n", (unsigned long long)std);
|
||||
encoder->norm = std;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7175_s_routing(struct v4l2_subdev *sd,
|
||||
u32 input, u32 output, u32 config)
|
||||
{
|
||||
struct adv7175 *encoder = to_adv7175(sd);
|
||||
|
||||
/* RJ: input = 0: input is from decoder
|
||||
input = 1: input is from ZR36060
|
||||
input = 2: color bar */
|
||||
|
||||
switch (input) {
|
||||
case 0:
|
||||
adv7175_write(sd, 0x01, 0x00);
|
||||
|
||||
if (encoder->norm & V4L2_STD_NTSC)
|
||||
set_subcarrier_freq(sd, 1);
|
||||
|
||||
adv7175_write(sd, 0x0c, TR1CAPT); /* TR1 */
|
||||
if (encoder->norm & V4L2_STD_SECAM)
|
||||
adv7175_write(sd, 0x0d, 0x49); /* Disable genlock */
|
||||
else
|
||||
adv7175_write(sd, 0x0d, 0x4f); /* Enable genlock */
|
||||
adv7175_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7175_write(sd, 0x07, TR0MODE);
|
||||
/*udelay(10);*/
|
||||
break;
|
||||
|
||||
case 1:
|
||||
adv7175_write(sd, 0x01, 0x00);
|
||||
|
||||
if (encoder->norm & V4L2_STD_NTSC)
|
||||
set_subcarrier_freq(sd, 0);
|
||||
|
||||
adv7175_write(sd, 0x0c, TR1PLAY); /* TR1 */
|
||||
adv7175_write(sd, 0x0d, 0x49);
|
||||
adv7175_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7175_write(sd, 0x07, TR0MODE);
|
||||
/* udelay(10); */
|
||||
break;
|
||||
|
||||
case 2:
|
||||
adv7175_write(sd, 0x01, 0x80);
|
||||
|
||||
if (encoder->norm & V4L2_STD_NTSC)
|
||||
set_subcarrier_freq(sd, 0);
|
||||
|
||||
adv7175_write(sd, 0x0d, 0x49);
|
||||
adv7175_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
adv7175_write(sd, 0x07, TR0MODE);
|
||||
/* udelay(10); */
|
||||
break;
|
||||
|
||||
default:
|
||||
v4l2_dbg(1, debug, sd, "illegal input: %d\n", input);
|
||||
return -EINVAL;
|
||||
}
|
||||
v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[input]);
|
||||
encoder->input = input;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7175_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
|
||||
enum v4l2_mbus_pixelcode *code)
|
||||
{
|
||||
if (index >= ARRAY_SIZE(adv7175_codes))
|
||||
return -EINVAL;
|
||||
|
||||
*code = adv7175_codes[index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7175_g_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *mf)
|
||||
{
|
||||
u8 val = adv7175_read(sd, 0x7);
|
||||
|
||||
if ((val & 0x40) == (1 << 6))
|
||||
mf->code = V4L2_MBUS_FMT_UYVY8_1X16;
|
||||
else
|
||||
mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
|
||||
|
||||
mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
mf->width = 0;
|
||||
mf->height = 0;
|
||||
mf->field = V4L2_FIELD_ANY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7175_s_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *mf)
|
||||
{
|
||||
u8 val = adv7175_read(sd, 0x7);
|
||||
int ret;
|
||||
|
||||
switch (mf->code) {
|
||||
case V4L2_MBUS_FMT_UYVY8_2X8:
|
||||
val &= ~0x40;
|
||||
break;
|
||||
|
||||
case V4L2_MBUS_FMT_UYVY8_1X16:
|
||||
val |= 0x40;
|
||||
break;
|
||||
|
||||
default:
|
||||
v4l2_dbg(1, debug, sd,
|
||||
"illegal v4l2_mbus_framefmt code: %d\n", mf->code);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = adv7175_write(sd, 0x7, val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0);
|
||||
}
|
||||
|
||||
static int adv7175_s_power(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
if (on)
|
||||
adv7175_write(sd, 0x01, 0x00);
|
||||
else
|
||||
adv7175_write(sd, 0x01, 0x78);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct v4l2_subdev_core_ops adv7175_core_ops = {
|
||||
.g_chip_ident = adv7175_g_chip_ident,
|
||||
.init = adv7175_init,
|
||||
.s_power = adv7175_s_power,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops adv7175_video_ops = {
|
||||
.s_std_output = adv7175_s_std_output,
|
||||
.s_routing = adv7175_s_routing,
|
||||
.s_mbus_fmt = adv7175_s_fmt,
|
||||
.g_mbus_fmt = adv7175_g_fmt,
|
||||
.enum_mbus_fmt = adv7175_enum_fmt,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops adv7175_ops = {
|
||||
.core = &adv7175_core_ops,
|
||||
.video = &adv7175_video_ops,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int adv7175_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i;
|
||||
struct adv7175 *encoder;
|
||||
struct v4l2_subdev *sd;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
encoder = kzalloc(sizeof(struct adv7175), GFP_KERNEL);
|
||||
if (encoder == NULL)
|
||||
return -ENOMEM;
|
||||
sd = &encoder->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &adv7175_ops);
|
||||
encoder->norm = V4L2_STD_NTSC;
|
||||
encoder->input = 0;
|
||||
|
||||
i = adv7175_write_block(sd, init_common, sizeof(init_common));
|
||||
if (i >= 0) {
|
||||
i = adv7175_write(sd, 0x07, TR0MODE | TR0RST);
|
||||
i = adv7175_write(sd, 0x07, TR0MODE);
|
||||
i = adv7175_read(sd, 0x12);
|
||||
v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
|
||||
}
|
||||
if (i < 0)
|
||||
v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7175_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(to_adv7175(sd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct i2c_device_id adv7175_id[] = {
|
||||
{ "adv7175", 0 },
|
||||
{ "adv7176", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adv7175_id);
|
||||
|
||||
static struct i2c_driver adv7175_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "adv7175",
|
||||
},
|
||||
.probe = adv7175_probe,
|
||||
.remove = adv7175_remove,
|
||||
.id_table = adv7175_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(adv7175_driver);
|
||||
667
drivers/media/i2c/adv7180.c
Normal file
667
drivers/media/i2c/adv7180.c
Normal file
|
|
@ -0,0 +1,667 @@
|
|||
/*
|
||||
* adv7180.c Analog Devices ADV7180 video decoder driver
|
||||
* Copyright (c) 2009 Intel Corporation
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define ADV7180_INPUT_CONTROL_REG 0x00
|
||||
#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00
|
||||
#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
|
||||
#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20
|
||||
#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30
|
||||
#define ADV7180_INPUT_CONTROL_NTSC_J 0x40
|
||||
#define ADV7180_INPUT_CONTROL_NTSC_M 0x50
|
||||
#define ADV7180_INPUT_CONTROL_PAL60 0x60
|
||||
#define ADV7180_INPUT_CONTROL_NTSC_443 0x70
|
||||
#define ADV7180_INPUT_CONTROL_PAL_BG 0x80
|
||||
#define ADV7180_INPUT_CONTROL_PAL_N 0x90
|
||||
#define ADV7180_INPUT_CONTROL_PAL_M 0xa0
|
||||
#define ADV7180_INPUT_CONTROL_PAL_M_PED 0xb0
|
||||
#define ADV7180_INPUT_CONTROL_PAL_COMB_N 0xc0
|
||||
#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED 0xd0
|
||||
#define ADV7180_INPUT_CONTROL_PAL_SECAM 0xe0
|
||||
#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED 0xf0
|
||||
#define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f
|
||||
|
||||
#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG 0x04
|
||||
#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5
|
||||
|
||||
#define ADV7180_AUTODETECT_ENABLE_REG 0x07
|
||||
#define ADV7180_AUTODETECT_DEFAULT 0x7f
|
||||
/* Contrast */
|
||||
#define ADV7180_CON_REG 0x08 /*Unsigned */
|
||||
#define ADV7180_CON_MIN 0
|
||||
#define ADV7180_CON_DEF 128
|
||||
#define ADV7180_CON_MAX 255
|
||||
/* Brightness*/
|
||||
#define ADV7180_BRI_REG 0x0a /*Signed */
|
||||
#define ADV7180_BRI_MIN -128
|
||||
#define ADV7180_BRI_DEF 0
|
||||
#define ADV7180_BRI_MAX 127
|
||||
/* Hue */
|
||||
#define ADV7180_HUE_REG 0x0b /*Signed, inverted */
|
||||
#define ADV7180_HUE_MIN -127
|
||||
#define ADV7180_HUE_DEF 0
|
||||
#define ADV7180_HUE_MAX 128
|
||||
|
||||
#define ADV7180_ADI_CTRL_REG 0x0e
|
||||
#define ADV7180_ADI_CTRL_IRQ_SPACE 0x20
|
||||
|
||||
#define ADV7180_PWR_MAN_REG 0x0f
|
||||
#define ADV7180_PWR_MAN_ON 0x04
|
||||
#define ADV7180_PWR_MAN_OFF 0x24
|
||||
#define ADV7180_PWR_MAN_RES 0x80
|
||||
|
||||
#define ADV7180_STATUS1_REG 0x10
|
||||
#define ADV7180_STATUS1_IN_LOCK 0x01
|
||||
#define ADV7180_STATUS1_AUTOD_MASK 0x70
|
||||
#define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00
|
||||
#define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10
|
||||
#define ADV7180_STATUS1_AUTOD_PAL_M 0x20
|
||||
#define ADV7180_STATUS1_AUTOD_PAL_60 0x30
|
||||
#define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40
|
||||
#define ADV7180_STATUS1_AUTOD_SECAM 0x50
|
||||
#define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60
|
||||
#define ADV7180_STATUS1_AUTOD_SECAM_525 0x70
|
||||
|
||||
#define ADV7180_IDENT_REG 0x11
|
||||
#define ADV7180_ID_7180 0x18
|
||||
|
||||
#define ADV7180_ICONF1_ADI 0x40
|
||||
#define ADV7180_ICONF1_ACTIVE_LOW 0x01
|
||||
#define ADV7180_ICONF1_PSYNC_ONLY 0x10
|
||||
#define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0
|
||||
/* Saturation */
|
||||
#define ADV7180_SD_SAT_CB_REG 0xe3 /*Unsigned */
|
||||
#define ADV7180_SD_SAT_CR_REG 0xe4 /*Unsigned */
|
||||
#define ADV7180_SAT_MIN 0
|
||||
#define ADV7180_SAT_DEF 128
|
||||
#define ADV7180_SAT_MAX 255
|
||||
|
||||
#define ADV7180_IRQ1_LOCK 0x01
|
||||
#define ADV7180_IRQ1_UNLOCK 0x02
|
||||
#define ADV7180_ISR1_ADI 0x42
|
||||
#define ADV7180_ICR1_ADI 0x43
|
||||
#define ADV7180_IMR1_ADI 0x44
|
||||
#define ADV7180_IMR2_ADI 0x48
|
||||
#define ADV7180_IRQ3_AD_CHANGE 0x08
|
||||
#define ADV7180_ISR3_ADI 0x4A
|
||||
#define ADV7180_ICR3_ADI 0x4B
|
||||
#define ADV7180_IMR3_ADI 0x4C
|
||||
#define ADV7180_IMR4_ADI 0x50
|
||||
|
||||
#define ADV7180_NTSC_V_BIT_END_REG 0xE6
|
||||
#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F
|
||||
|
||||
struct adv7180_state {
|
||||
struct v4l2_ctrl_handler ctrl_hdl;
|
||||
struct v4l2_subdev sd;
|
||||
struct work_struct work;
|
||||
struct mutex mutex; /* mutual excl. when accessing chip */
|
||||
int irq;
|
||||
v4l2_std_id curr_norm;
|
||||
bool autodetect;
|
||||
u8 input;
|
||||
};
|
||||
#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
|
||||
struct adv7180_state, \
|
||||
ctrl_hdl)->sd)
|
||||
|
||||
static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
|
||||
{
|
||||
switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
|
||||
case ADV7180_STATUS1_AUTOD_NTSM_M_J:
|
||||
return V4L2_STD_NTSC;
|
||||
case ADV7180_STATUS1_AUTOD_NTSC_4_43:
|
||||
return V4L2_STD_NTSC_443;
|
||||
case ADV7180_STATUS1_AUTOD_PAL_M:
|
||||
return V4L2_STD_PAL_M;
|
||||
case ADV7180_STATUS1_AUTOD_PAL_60:
|
||||
return V4L2_STD_PAL_60;
|
||||
case ADV7180_STATUS1_AUTOD_PAL_B_G:
|
||||
return V4L2_STD_PAL;
|
||||
case ADV7180_STATUS1_AUTOD_SECAM:
|
||||
return V4L2_STD_SECAM;
|
||||
case ADV7180_STATUS1_AUTOD_PAL_COMB:
|
||||
return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
|
||||
case ADV7180_STATUS1_AUTOD_SECAM_525:
|
||||
return V4L2_STD_SECAM;
|
||||
default:
|
||||
return V4L2_STD_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static int v4l2_std_to_adv7180(v4l2_std_id std)
|
||||
{
|
||||
if (std == V4L2_STD_PAL_60)
|
||||
return ADV7180_INPUT_CONTROL_PAL60;
|
||||
if (std == V4L2_STD_NTSC_443)
|
||||
return ADV7180_INPUT_CONTROL_NTSC_443;
|
||||
if (std == V4L2_STD_PAL_N)
|
||||
return ADV7180_INPUT_CONTROL_PAL_N;
|
||||
if (std == V4L2_STD_PAL_M)
|
||||
return ADV7180_INPUT_CONTROL_PAL_M;
|
||||
if (std == V4L2_STD_PAL_Nc)
|
||||
return ADV7180_INPUT_CONTROL_PAL_COMB_N;
|
||||
|
||||
if (std & V4L2_STD_PAL)
|
||||
return ADV7180_INPUT_CONTROL_PAL_BG;
|
||||
if (std & V4L2_STD_NTSC)
|
||||
return ADV7180_INPUT_CONTROL_NTSC_M;
|
||||
if (std & V4L2_STD_SECAM)
|
||||
return ADV7180_INPUT_CONTROL_PAL_SECAM;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static u32 adv7180_status_to_v4l2(u8 status1)
|
||||
{
|
||||
if (!(status1 & ADV7180_STATUS1_IN_LOCK))
|
||||
return V4L2_IN_ST_NO_SIGNAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __adv7180_status(struct i2c_client *client, u32 *status,
|
||||
v4l2_std_id *std)
|
||||
{
|
||||
int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
|
||||
|
||||
if (status1 < 0)
|
||||
return status1;
|
||||
|
||||
if (status)
|
||||
*status = adv7180_status_to_v4l2(status1);
|
||||
if (std)
|
||||
*std = adv7180_std_to_v4l2(status1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct adv7180_state, sd);
|
||||
}
|
||||
|
||||
static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
int err = mutex_lock_interruptible(&state->mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* when we are interrupt driven we know the state */
|
||||
if (!state->autodetect || state->irq > 0)
|
||||
*std = state->curr_norm;
|
||||
else
|
||||
err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
|
||||
|
||||
mutex_unlock(&state->mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
|
||||
u32 output, u32 config)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
int ret = mutex_lock_interruptible(&state->mutex);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
|
||||
* all inputs and let the card driver take care of validation
|
||||
*/
|
||||
if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
|
||||
goto out;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
ADV7180_INPUT_CONTROL_REG, ret | input);
|
||||
state->input = input;
|
||||
out:
|
||||
mutex_unlock(&state->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
int ret = mutex_lock_interruptible(&state->mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
|
||||
mutex_unlock(&state->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
|
||||
struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0);
|
||||
}
|
||||
|
||||
static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
int ret = mutex_lock_interruptible(&state->mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* all standards -> autodetect */
|
||||
if (std == V4L2_STD_ALL) {
|
||||
ret =
|
||||
i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
|
||||
ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
|
||||
| state->input);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
__adv7180_status(client, NULL, &state->curr_norm);
|
||||
state->autodetect = true;
|
||||
} else {
|
||||
ret = v4l2_std_to_adv7180(std);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
ADV7180_INPUT_CONTROL_REG,
|
||||
ret | state->input);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
state->curr_norm = std;
|
||||
state->autodetect = false;
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
mutex_unlock(&state->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
int ret = mutex_lock_interruptible(&state->mutex);
|
||||
int val;
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
val = ctrl->val;
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_BRIGHTNESS:
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, val);
|
||||
break;
|
||||
case V4L2_CID_HUE:
|
||||
/*Hue is inverted according to HSL chart */
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, -val);
|
||||
break;
|
||||
case V4L2_CID_CONTRAST:
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, val);
|
||||
break;
|
||||
case V4L2_CID_SATURATION:
|
||||
/*
|
||||
*This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
|
||||
*Let's not confuse the user, everybody understands saturation
|
||||
*/
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG,
|
||||
val);
|
||||
if (ret < 0)
|
||||
break;
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG,
|
||||
val);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&state->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
|
||||
.s_ctrl = adv7180_s_ctrl,
|
||||
};
|
||||
|
||||
static int adv7180_init_controls(struct adv7180_state *state)
|
||||
{
|
||||
v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
|
||||
|
||||
v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
|
||||
V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN,
|
||||
ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF);
|
||||
v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
|
||||
V4L2_CID_CONTRAST, ADV7180_CON_MIN,
|
||||
ADV7180_CON_MAX, 1, ADV7180_CON_DEF);
|
||||
v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
|
||||
V4L2_CID_SATURATION, ADV7180_SAT_MIN,
|
||||
ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF);
|
||||
v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
|
||||
V4L2_CID_HUE, ADV7180_HUE_MIN,
|
||||
ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
|
||||
state->sd.ctrl_handler = &state->ctrl_hdl;
|
||||
if (state->ctrl_hdl.error) {
|
||||
int err = state->ctrl_hdl.error;
|
||||
|
||||
v4l2_ctrl_handler_free(&state->ctrl_hdl);
|
||||
return err;
|
||||
}
|
||||
v4l2_ctrl_handler_setup(&state->ctrl_hdl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static void adv7180_exit_controls(struct adv7180_state *state)
|
||||
{
|
||||
v4l2_ctrl_handler_free(&state->ctrl_hdl);
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
|
||||
.querystd = adv7180_querystd,
|
||||
.g_input_status = adv7180_g_input_status,
|
||||
.s_routing = adv7180_s_routing,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
|
||||
.g_chip_ident = adv7180_g_chip_ident,
|
||||
.s_std = adv7180_s_std,
|
||||
.queryctrl = v4l2_subdev_queryctrl,
|
||||
.g_ctrl = v4l2_subdev_g_ctrl,
|
||||
.s_ctrl = v4l2_subdev_s_ctrl,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops adv7180_ops = {
|
||||
.core = &adv7180_core_ops,
|
||||
.video = &adv7180_video_ops,
|
||||
};
|
||||
|
||||
static void adv7180_work(struct work_struct *work)
|
||||
{
|
||||
struct adv7180_state *state = container_of(work, struct adv7180_state,
|
||||
work);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
|
||||
u8 isr3;
|
||||
|
||||
mutex_lock(&state->mutex);
|
||||
i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
|
||||
ADV7180_ADI_CTRL_IRQ_SPACE);
|
||||
isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
|
||||
/* clear */
|
||||
i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
|
||||
i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
|
||||
|
||||
if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
|
||||
__adv7180_status(client, NULL, &state->curr_norm);
|
||||
mutex_unlock(&state->mutex);
|
||||
|
||||
enable_irq(state->irq);
|
||||
}
|
||||
|
||||
static irqreturn_t adv7180_irq(int irq, void *devid)
|
||||
{
|
||||
struct adv7180_state *state = devid;
|
||||
|
||||
schedule_work(&state->work);
|
||||
|
||||
disable_irq_nosync(state->irq);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int init_device(struct i2c_client *client, struct adv7180_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Initialize adv7180 */
|
||||
/* Enable autodetection */
|
||||
if (state->autodetect) {
|
||||
ret =
|
||||
i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
|
||||
ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
|
||||
| state->input);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret =
|
||||
i2c_smbus_write_byte_data(client,
|
||||
ADV7180_AUTODETECT_ENABLE_REG,
|
||||
ADV7180_AUTODETECT_DEFAULT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
ret = v4l2_std_to_adv7180(state->curr_norm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret =
|
||||
i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
|
||||
ret | state->input);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
}
|
||||
/* ITU-R BT.656-4 compatible */
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
|
||||
ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Manually set V bit end position in NTSC mode */
|
||||
ret = i2c_smbus_write_byte_data(client,
|
||||
ADV7180_NTSC_V_BIT_END_REG,
|
||||
ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* read current norm */
|
||||
__adv7180_status(client, NULL, &state->curr_norm);
|
||||
|
||||
/* register for interrupts */
|
||||
if (state->irq > 0) {
|
||||
ret = request_irq(state->irq, adv7180_irq, 0, KBUILD_MODNAME,
|
||||
state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
|
||||
ADV7180_ADI_CTRL_IRQ_SPACE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* config the Interrupt pin to be active low */
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
|
||||
ADV7180_ICONF1_ACTIVE_LOW |
|
||||
ADV7180_ICONF1_PSYNC_ONLY);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* enable AD change interrupts interrupts */
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
|
||||
ADV7180_IRQ3_AD_CHANGE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
|
||||
0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __devinit int adv7180_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adv7180_state *state;
|
||||
struct v4l2_subdev *sd;
|
||||
int ret;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
||||
v4l_info(client, "chip found @ 0x%02x (%s)\n",
|
||||
client->addr, client->adapter->name);
|
||||
|
||||
state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
|
||||
if (state == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
state->irq = client->irq;
|
||||
INIT_WORK(&state->work, adv7180_work);
|
||||
mutex_init(&state->mutex);
|
||||
state->autodetect = true;
|
||||
state->input = 0;
|
||||
sd = &state->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
|
||||
|
||||
ret = adv7180_init_controls(state);
|
||||
if (ret)
|
||||
goto err_unreg_subdev;
|
||||
ret = init_device(client, state);
|
||||
if (ret)
|
||||
goto err_free_ctrl;
|
||||
return 0;
|
||||
|
||||
err_free_ctrl:
|
||||
adv7180_exit_controls(state);
|
||||
err_unreg_subdev:
|
||||
mutex_destroy(&state->mutex);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(state);
|
||||
err:
|
||||
printk(KERN_ERR KBUILD_MODNAME ": Failed to probe: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devexit int adv7180_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
|
||||
if (state->irq > 0) {
|
||||
free_irq(client->irq, state);
|
||||
if (cancel_work_sync(&state->work)) {
|
||||
/*
|
||||
* Work was pending, therefore we need to enable
|
||||
* IRQ here to balance the disable_irq() done in the
|
||||
* interrupt handler.
|
||||
*/
|
||||
enable_irq(state->irq);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_destroy(&state->mutex);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(to_state(sd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adv7180_id[] = {
|
||||
{KBUILD_MODNAME, 0},
|
||||
{},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int adv7180_suspend(struct i2c_client *client, pm_message_t state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
|
||||
ADV7180_PWR_MAN_OFF);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_resume(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
|
||||
ADV7180_PWR_MAN_ON);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = init_device(client, state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, adv7180_id);
|
||||
|
||||
static struct i2c_driver adv7180_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = KBUILD_MODNAME,
|
||||
},
|
||||
.probe = adv7180_probe,
|
||||
.remove = __devexit_p(adv7180_remove),
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = adv7180_suspend,
|
||||
.resume = adv7180_resume,
|
||||
#endif
|
||||
.id_table = adv7180_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(adv7180_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
|
||||
MODULE_AUTHOR("Mocean Laboratories");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
699
drivers/media/i2c/adv7183.c
Normal file
699
drivers/media/i2c/adv7183.c
Normal file
|
|
@ -0,0 +1,699 @@
|
|||
/*
|
||||
* adv7183.c Analog Devices ADV7183 video decoder driver
|
||||
*
|
||||
* Copyright (c) 2011 Analog Devices Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include <media/adv7183.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
|
||||
#include "adv7183_regs.h"
|
||||
|
||||
struct adv7183 {
|
||||
struct v4l2_subdev sd;
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
|
||||
v4l2_std_id std; /* Current set standard */
|
||||
u32 input;
|
||||
u32 output;
|
||||
unsigned reset_pin;
|
||||
unsigned oe_pin;
|
||||
struct v4l2_mbus_framefmt fmt;
|
||||
};
|
||||
|
||||
/* EXAMPLES USING 27 MHz CLOCK
|
||||
* Mode 1 CVBS Input (Composite Video on AIN5)
|
||||
* All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8.
|
||||
*/
|
||||
static const unsigned char adv7183_init_regs[] = {
|
||||
ADV7183_IN_CTRL, 0x04, /* CVBS input on AIN5 */
|
||||
ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */
|
||||
ADV7183_SHAP_FILT_CTRL, 0x41, /* Set CSFM to SH1 */
|
||||
ADV7183_ADC_CTRL, 0x16, /* Power down ADC 1 and ADC 2 */
|
||||
ADV7183_CTI_DNR_CTRL_4, 0x04, /* Set DNR threshold to 4 for flat response */
|
||||
/* ADI recommended programming sequence */
|
||||
ADV7183_ADI_CTRL, 0x80,
|
||||
ADV7183_CTI_DNR_CTRL_4, 0x20,
|
||||
0x52, 0x18,
|
||||
0x58, 0xED,
|
||||
0x77, 0xC5,
|
||||
0x7C, 0x93,
|
||||
0x7D, 0x00,
|
||||
0xD0, 0x48,
|
||||
0xD5, 0xA0,
|
||||
0xD7, 0xEA,
|
||||
ADV7183_SD_SATURATION_CR, 0x3E,
|
||||
ADV7183_PAL_V_END, 0x3E,
|
||||
ADV7183_PAL_F_TOGGLE, 0x0F,
|
||||
ADV7183_ADI_CTRL, 0x00,
|
||||
};
|
||||
|
||||
static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct adv7183, sd);
|
||||
}
|
||||
static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
return &container_of(ctrl->handler, struct adv7183, hdl)->sd;
|
||||
}
|
||||
|
||||
static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg,
|
||||
unsigned char value)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static int adv7183_writeregs(struct v4l2_subdev *sd,
|
||||
const unsigned char *regs, unsigned int num)
|
||||
{
|
||||
unsigned char reg, data;
|
||||
unsigned int cnt = 0;
|
||||
|
||||
if (num & 0x1) {
|
||||
v4l2_err(sd, "invalid regs array\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (cnt < num) {
|
||||
reg = *regs++;
|
||||
data = *regs++;
|
||||
cnt += 2;
|
||||
|
||||
adv7183_write(sd, reg, data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_log_status(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct adv7183 *decoder = to_adv7183(sd);
|
||||
|
||||
v4l2_info(sd, "adv7183: Input control = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_IN_CTRL));
|
||||
v4l2_info(sd, "adv7183: Video selection = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_VD_SEL));
|
||||
v4l2_info(sd, "adv7183: Output control = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_OUT_CTRL));
|
||||
v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_EXT_OUT_CTRL));
|
||||
v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_AUTO_DET_EN));
|
||||
v4l2_info(sd, "adv7183: Contrast = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_CONTRAST));
|
||||
v4l2_info(sd, "adv7183: Brightness = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_BRIGHTNESS));
|
||||
v4l2_info(sd, "adv7183: Hue = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_HUE));
|
||||
v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_DEF_Y));
|
||||
v4l2_info(sd, "adv7183: Default value C = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_DEF_C));
|
||||
v4l2_info(sd, "adv7183: ADI control = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_ADI_CTRL));
|
||||
v4l2_info(sd, "adv7183: Power Management = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_POW_MANAGE));
|
||||
v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_STATUS_1),
|
||||
adv7183_read(sd, ADV7183_STATUS_2),
|
||||
adv7183_read(sd, ADV7183_STATUS_3));
|
||||
v4l2_info(sd, "adv7183: Ident = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_IDENT));
|
||||
v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL));
|
||||
v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1));
|
||||
v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_SHAP_FILT_CTRL),
|
||||
adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2));
|
||||
v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_COMB_FILT_CTRL));
|
||||
v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_ADI_CTRL_2));
|
||||
v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_PIX_DELAY_CTRL));
|
||||
v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_MISC_GAIN_CTRL));
|
||||
v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_AGC_MODE_CTRL));
|
||||
v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1),
|
||||
adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2));
|
||||
v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1),
|
||||
adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2));
|
||||
v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1),
|
||||
adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2),
|
||||
adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3));
|
||||
v4l2_info(sd, "adv7183: Hsync positon control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_HS_POS_CTRL_1),
|
||||
adv7183_read(sd, ADV7183_HS_POS_CTRL_2),
|
||||
adv7183_read(sd, ADV7183_HS_POS_CTRL_3));
|
||||
v4l2_info(sd, "adv7183: Polarity = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_POLARITY));
|
||||
v4l2_info(sd, "adv7183: ADC control = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_ADC_CTRL));
|
||||
v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_SD_OFFSET_CB),
|
||||
adv7183_read(sd, ADV7183_SD_OFFSET_CR));
|
||||
v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_SD_SATURATION_CB),
|
||||
adv7183_read(sd, ADV7183_SD_SATURATION_CR));
|
||||
v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n",
|
||||
adv7183_read(sd, ADV7183_DRIVE_STR));
|
||||
v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
|
||||
{
|
||||
struct adv7183 *decoder = to_adv7183(sd);
|
||||
|
||||
*std = decoder->std;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct adv7183 *decoder = to_adv7183(sd);
|
||||
int reg;
|
||||
|
||||
reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
|
||||
if (std == V4L2_STD_PAL_60)
|
||||
reg |= 0x60;
|
||||
else if (std == V4L2_STD_NTSC_443)
|
||||
reg |= 0x70;
|
||||
else if (std == V4L2_STD_PAL_N)
|
||||
reg |= 0x90;
|
||||
else if (std == V4L2_STD_PAL_M)
|
||||
reg |= 0xA0;
|
||||
else if (std == V4L2_STD_PAL_Nc)
|
||||
reg |= 0xC0;
|
||||
else if (std & V4L2_STD_PAL)
|
||||
reg |= 0x80;
|
||||
else if (std & V4L2_STD_NTSC)
|
||||
reg |= 0x50;
|
||||
else if (std & V4L2_STD_SECAM)
|
||||
reg |= 0xE0;
|
||||
else
|
||||
return -EINVAL;
|
||||
adv7183_write(sd, ADV7183_IN_CTRL, reg);
|
||||
|
||||
decoder->std = std;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_reset(struct v4l2_subdev *sd, u32 val)
|
||||
{
|
||||
int reg;
|
||||
|
||||
reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80;
|
||||
adv7183_write(sd, ADV7183_POW_MANAGE, reg);
|
||||
/* wait 5ms before any further i2c writes are performed */
|
||||
usleep_range(5000, 10000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_s_routing(struct v4l2_subdev *sd,
|
||||
u32 input, u32 output, u32 config)
|
||||
{
|
||||
struct adv7183 *decoder = to_adv7183(sd);
|
||||
int reg;
|
||||
|
||||
if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT))
|
||||
return -EINVAL;
|
||||
|
||||
if (input != decoder->input) {
|
||||
decoder->input = input;
|
||||
reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0;
|
||||
switch (input) {
|
||||
case ADV7183_COMPOSITE1:
|
||||
reg |= 0x1;
|
||||
break;
|
||||
case ADV7183_COMPOSITE2:
|
||||
reg |= 0x2;
|
||||
break;
|
||||
case ADV7183_COMPOSITE3:
|
||||
reg |= 0x3;
|
||||
break;
|
||||
case ADV7183_COMPOSITE4:
|
||||
reg |= 0x4;
|
||||
break;
|
||||
case ADV7183_COMPOSITE5:
|
||||
reg |= 0x5;
|
||||
break;
|
||||
case ADV7183_COMPOSITE6:
|
||||
reg |= 0xB;
|
||||
break;
|
||||
case ADV7183_COMPOSITE7:
|
||||
reg |= 0xC;
|
||||
break;
|
||||
case ADV7183_COMPOSITE8:
|
||||
reg |= 0xD;
|
||||
break;
|
||||
case ADV7183_COMPOSITE9:
|
||||
reg |= 0xE;
|
||||
break;
|
||||
case ADV7183_COMPOSITE10:
|
||||
reg |= 0xF;
|
||||
break;
|
||||
case ADV7183_SVIDEO0:
|
||||
reg |= 0x6;
|
||||
break;
|
||||
case ADV7183_SVIDEO1:
|
||||
reg |= 0x7;
|
||||
break;
|
||||
case ADV7183_SVIDEO2:
|
||||
reg |= 0x8;
|
||||
break;
|
||||
case ADV7183_COMPONENT0:
|
||||
reg |= 0x9;
|
||||
break;
|
||||
case ADV7183_COMPONENT1:
|
||||
reg |= 0xA;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
adv7183_write(sd, ADV7183_IN_CTRL, reg);
|
||||
}
|
||||
|
||||
if (output != decoder->output) {
|
||||
decoder->output = output;
|
||||
reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0;
|
||||
switch (output) {
|
||||
case ADV7183_16BIT_OUT:
|
||||
reg |= 0x9;
|
||||
break;
|
||||
default:
|
||||
reg |= 0xC;
|
||||
break;
|
||||
}
|
||||
adv7183_write(sd, ADV7183_OUT_CTRL, reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct v4l2_subdev *sd = to_sd(ctrl);
|
||||
int val = ctrl->val;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_BRIGHTNESS:
|
||||
if (val < 0)
|
||||
val = 127 - val;
|
||||
adv7183_write(sd, ADV7183_BRIGHTNESS, val);
|
||||
break;
|
||||
case V4L2_CID_CONTRAST:
|
||||
adv7183_write(sd, ADV7183_CONTRAST, val);
|
||||
break;
|
||||
case V4L2_CID_SATURATION:
|
||||
adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8);
|
||||
adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF));
|
||||
break;
|
||||
case V4L2_CID_HUE:
|
||||
adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8);
|
||||
adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF));
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
|
||||
{
|
||||
struct adv7183 *decoder = to_adv7183(sd);
|
||||
int reg;
|
||||
|
||||
/* enable autodetection block */
|
||||
reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF;
|
||||
adv7183_write(sd, ADV7183_IN_CTRL, reg);
|
||||
|
||||
/* wait autodetection switch */
|
||||
mdelay(10);
|
||||
|
||||
/* get autodetection result */
|
||||
reg = adv7183_read(sd, ADV7183_STATUS_1);
|
||||
switch ((reg >> 0x4) & 0x7) {
|
||||
case 0:
|
||||
*std = V4L2_STD_NTSC;
|
||||
break;
|
||||
case 1:
|
||||
*std = V4L2_STD_NTSC_443;
|
||||
break;
|
||||
case 2:
|
||||
*std = V4L2_STD_PAL_M;
|
||||
break;
|
||||
case 3:
|
||||
*std = V4L2_STD_PAL_60;
|
||||
break;
|
||||
case 4:
|
||||
*std = V4L2_STD_PAL;
|
||||
break;
|
||||
case 5:
|
||||
*std = V4L2_STD_SECAM;
|
||||
break;
|
||||
case 6:
|
||||
*std = V4L2_STD_PAL_Nc;
|
||||
break;
|
||||
case 7:
|
||||
*std = V4L2_STD_SECAM;
|
||||
break;
|
||||
default:
|
||||
*std = V4L2_STD_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
/* after std detection, write back user set std */
|
||||
adv7183_s_std(sd, decoder->std);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
|
||||
{
|
||||
int reg;
|
||||
|
||||
*status = V4L2_IN_ST_NO_SIGNAL;
|
||||
reg = adv7183_read(sd, ADV7183_STATUS_1);
|
||||
if (reg < 0)
|
||||
return reg;
|
||||
if (reg & 0x1)
|
||||
*status = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
|
||||
enum v4l2_mbus_pixelcode *code)
|
||||
{
|
||||
if (index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
*code = V4L2_MBUS_FMT_UYVY8_2X8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *fmt)
|
||||
{
|
||||
struct adv7183 *decoder = to_adv7183(sd);
|
||||
|
||||
fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
|
||||
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
if (decoder->std & V4L2_STD_525_60) {
|
||||
fmt->field = V4L2_FIELD_SEQ_TB;
|
||||
fmt->width = 720;
|
||||
fmt->height = 480;
|
||||
} else {
|
||||
fmt->field = V4L2_FIELD_SEQ_BT;
|
||||
fmt->width = 720;
|
||||
fmt->height = 576;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *fmt)
|
||||
{
|
||||
struct adv7183 *decoder = to_adv7183(sd);
|
||||
|
||||
adv7183_try_mbus_fmt(sd, fmt);
|
||||
decoder->fmt = *fmt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *fmt)
|
||||
{
|
||||
struct adv7183 *decoder = to_adv7183(sd);
|
||||
|
||||
*fmt = decoder->fmt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
{
|
||||
struct adv7183 *decoder = to_adv7183(sd);
|
||||
|
||||
if (enable)
|
||||
gpio_direction_output(decoder->oe_pin, 0);
|
||||
else
|
||||
gpio_direction_output(decoder->oe_pin, 1);
|
||||
udelay(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_g_chip_ident(struct v4l2_subdev *sd,
|
||||
struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
int rev;
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
/* 0x11 for adv7183, 0x13 for adv7183b */
|
||||
rev = adv7183_read(sd, ADV7183_IDENT);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7183, rev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
if (!v4l2_chip_match_i2c_client(client, ®->match))
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
reg->val = adv7183_read(sd, reg->reg & 0xff);
|
||||
reg->size = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
if (!v4l2_chip_match_i2c_client(client, ®->match))
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct v4l2_ctrl_ops adv7183_ctrl_ops = {
|
||||
.s_ctrl = adv7183_s_ctrl,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops adv7183_core_ops = {
|
||||
.log_status = adv7183_log_status,
|
||||
.g_std = adv7183_g_std,
|
||||
.s_std = adv7183_s_std,
|
||||
.reset = adv7183_reset,
|
||||
.g_chip_ident = adv7183_g_chip_ident,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
.g_register = adv7183_g_register,
|
||||
.s_register = adv7183_s_register,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops adv7183_video_ops = {
|
||||
.s_routing = adv7183_s_routing,
|
||||
.querystd = adv7183_querystd,
|
||||
.g_input_status = adv7183_g_input_status,
|
||||
.enum_mbus_fmt = adv7183_enum_mbus_fmt,
|
||||
.try_mbus_fmt = adv7183_try_mbus_fmt,
|
||||
.s_mbus_fmt = adv7183_s_mbus_fmt,
|
||||
.g_mbus_fmt = adv7183_g_mbus_fmt,
|
||||
.s_stream = adv7183_s_stream,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops adv7183_ops = {
|
||||
.core = &adv7183_core_ops,
|
||||
.video = &adv7183_video_ops,
|
||||
};
|
||||
|
||||
static int adv7183_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adv7183 *decoder;
|
||||
struct v4l2_subdev *sd;
|
||||
struct v4l2_ctrl_handler *hdl;
|
||||
int ret;
|
||||
struct v4l2_mbus_framefmt fmt;
|
||||
const unsigned *pin_array;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
||||
v4l_info(client, "chip found @ 0x%02x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
pin_array = client->dev.platform_data;
|
||||
if (pin_array == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
decoder = kzalloc(sizeof(struct adv7183), GFP_KERNEL);
|
||||
if (decoder == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
decoder->reset_pin = pin_array[0];
|
||||
decoder->oe_pin = pin_array[1];
|
||||
|
||||
if (gpio_request(decoder->reset_pin, "ADV7183 Reset")) {
|
||||
v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin);
|
||||
ret = -EBUSY;
|
||||
goto err_free_decoder;
|
||||
}
|
||||
|
||||
if (gpio_request(decoder->oe_pin, "ADV7183 Output Enable")) {
|
||||
v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin);
|
||||
ret = -EBUSY;
|
||||
goto err_free_reset;
|
||||
}
|
||||
|
||||
sd = &decoder->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &adv7183_ops);
|
||||
|
||||
hdl = &decoder->hdl;
|
||||
v4l2_ctrl_handler_init(hdl, 4);
|
||||
v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
|
||||
V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
|
||||
v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
|
||||
V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80);
|
||||
v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
|
||||
V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080);
|
||||
v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops,
|
||||
V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080);
|
||||
/* hook the control handler into the driver */
|
||||
sd->ctrl_handler = hdl;
|
||||
if (hdl->error) {
|
||||
ret = hdl->error;
|
||||
|
||||
v4l2_ctrl_handler_free(hdl);
|
||||
goto err_free_oe;
|
||||
}
|
||||
|
||||
/* v4l2 doesn't support an autodetect standard, pick PAL as default */
|
||||
decoder->std = V4L2_STD_PAL;
|
||||
decoder->input = ADV7183_COMPOSITE4;
|
||||
decoder->output = ADV7183_8BIT_OUT;
|
||||
|
||||
gpio_direction_output(decoder->oe_pin, 1);
|
||||
/* reset chip */
|
||||
gpio_direction_output(decoder->reset_pin, 0);
|
||||
/* reset pulse width at least 5ms */
|
||||
mdelay(10);
|
||||
gpio_direction_output(decoder->reset_pin, 1);
|
||||
/* wait 5ms before any further i2c writes are performed */
|
||||
mdelay(5);
|
||||
|
||||
adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs));
|
||||
adv7183_s_std(sd, decoder->std);
|
||||
fmt.width = 720;
|
||||
fmt.height = 576;
|
||||
adv7183_s_mbus_fmt(sd, &fmt);
|
||||
|
||||
/* initialize the hardware to the default control values */
|
||||
ret = v4l2_ctrl_handler_setup(hdl);
|
||||
if (ret) {
|
||||
v4l2_ctrl_handler_free(hdl);
|
||||
goto err_free_oe;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_free_oe:
|
||||
gpio_free(decoder->oe_pin);
|
||||
err_free_reset:
|
||||
gpio_free(decoder->reset_pin);
|
||||
err_free_decoder:
|
||||
kfree(decoder);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adv7183_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct adv7183 *decoder = to_adv7183(sd);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(sd->ctrl_handler);
|
||||
gpio_free(decoder->oe_pin);
|
||||
gpio_free(decoder->reset_pin);
|
||||
kfree(decoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adv7183_id[] = {
|
||||
{"adv7183", 0},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, adv7183_id);
|
||||
|
||||
static struct i2c_driver adv7183_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "adv7183",
|
||||
},
|
||||
.probe = adv7183_probe,
|
||||
.remove = __devexit_p(adv7183_remove),
|
||||
.id_table = adv7183_id,
|
||||
};
|
||||
|
||||
static __init int adv7183_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adv7183_driver);
|
||||
}
|
||||
|
||||
static __exit void adv7183_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adv7183_driver);
|
||||
}
|
||||
|
||||
module_init(adv7183_init);
|
||||
module_exit(adv7183_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver");
|
||||
MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
107
drivers/media/i2c/adv7183_regs.h
Normal file
107
drivers/media/i2c/adv7183_regs.h
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* adv7183 - Analog Devices ADV7183 video decoder registers
|
||||
*
|
||||
* Copyright (c) 2011 Analog Devices Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _ADV7183_REGS_H_
|
||||
#define _ADV7183_REGS_H_
|
||||
|
||||
#define ADV7183_IN_CTRL 0x00 /* Input control */
|
||||
#define ADV7183_VD_SEL 0x01 /* Video selection */
|
||||
#define ADV7183_OUT_CTRL 0x03 /* Output control */
|
||||
#define ADV7183_EXT_OUT_CTRL 0x04 /* Extended output control */
|
||||
#define ADV7183_AUTO_DET_EN 0x07 /* Autodetect enable */
|
||||
#define ADV7183_CONTRAST 0x08 /* Contrast */
|
||||
#define ADV7183_BRIGHTNESS 0x0A /* Brightness */
|
||||
#define ADV7183_HUE 0x0B /* Hue */
|
||||
#define ADV7183_DEF_Y 0x0C /* Default value Y */
|
||||
#define ADV7183_DEF_C 0x0D /* Default value C */
|
||||
#define ADV7183_ADI_CTRL 0x0E /* ADI control */
|
||||
#define ADV7183_POW_MANAGE 0x0F /* Power Management */
|
||||
#define ADV7183_STATUS_1 0x10 /* Status 1 */
|
||||
#define ADV7183_IDENT 0x11 /* Ident */
|
||||
#define ADV7183_STATUS_2 0x12 /* Status 2 */
|
||||
#define ADV7183_STATUS_3 0x13 /* Status 3 */
|
||||
#define ADV7183_ANAL_CLAMP_CTRL 0x14 /* Analog clamp control */
|
||||
#define ADV7183_DIGI_CLAMP_CTRL_1 0x15 /* Digital clamp control 1 */
|
||||
#define ADV7183_SHAP_FILT_CTRL 0x17 /* Shaping filter control */
|
||||
#define ADV7183_SHAP_FILT_CTRL_2 0x18 /* Shaping filter control 2 */
|
||||
#define ADV7183_COMB_FILT_CTRL 0x19 /* Comb filter control */
|
||||
#define ADV7183_ADI_CTRL_2 0x1D /* ADI control 2 */
|
||||
#define ADV7183_PIX_DELAY_CTRL 0x27 /* Pixel delay control */
|
||||
#define ADV7183_MISC_GAIN_CTRL 0x2B /* Misc gain control */
|
||||
#define ADV7183_AGC_MODE_CTRL 0x2C /* AGC mode control */
|
||||
#define ADV7183_CHRO_GAIN_CTRL_1 0x2D /* Chroma gain control 1 */
|
||||
#define ADV7183_CHRO_GAIN_CTRL_2 0x2E /* Chroma gain control 2 */
|
||||
#define ADV7183_LUMA_GAIN_CTRL_1 0x2F /* Luma gain control 1 */
|
||||
#define ADV7183_LUMA_GAIN_CTRL_2 0x30 /* Luma gain control 2 */
|
||||
#define ADV7183_VS_FIELD_CTRL_1 0x31 /* Vsync field control 1 */
|
||||
#define ADV7183_VS_FIELD_CTRL_2 0x32 /* Vsync field control 2 */
|
||||
#define ADV7183_VS_FIELD_CTRL_3 0x33 /* Vsync field control 3 */
|
||||
#define ADV7183_HS_POS_CTRL_1 0x34 /* Hsync positon control 1 */
|
||||
#define ADV7183_HS_POS_CTRL_2 0x35 /* Hsync positon control 2 */
|
||||
#define ADV7183_HS_POS_CTRL_3 0x36 /* Hsync positon control 3 */
|
||||
#define ADV7183_POLARITY 0x37 /* Polarity */
|
||||
#define ADV7183_NTSC_COMB_CTRL 0x38 /* NTSC comb control */
|
||||
#define ADV7183_PAL_COMB_CTRL 0x39 /* PAL comb control */
|
||||
#define ADV7183_ADC_CTRL 0x3A /* ADC control */
|
||||
#define ADV7183_MAN_WIN_CTRL 0x3D /* Manual window control */
|
||||
#define ADV7183_RESAMPLE_CTRL 0x41 /* Resample control */
|
||||
#define ADV7183_GEMSTAR_CTRL_1 0x48 /* Gemstar ctrl 1 */
|
||||
#define ADV7183_GEMSTAR_CTRL_2 0x49 /* Gemstar ctrl 2 */
|
||||
#define ADV7183_GEMSTAR_CTRL_3 0x4A /* Gemstar ctrl 3 */
|
||||
#define ADV7183_GEMSTAR_CTRL_4 0x4B /* Gemstar ctrl 4 */
|
||||
#define ADV7183_GEMSTAR_CTRL_5 0x4C /* Gemstar ctrl 5 */
|
||||
#define ADV7183_CTI_DNR_CTRL_1 0x4D /* CTI DNR ctrl 1 */
|
||||
#define ADV7183_CTI_DNR_CTRL_2 0x4E /* CTI DNR ctrl 2 */
|
||||
#define ADV7183_CTI_DNR_CTRL_4 0x50 /* CTI DNR ctrl 4 */
|
||||
#define ADV7183_LOCK_CNT 0x51 /* Lock count */
|
||||
#define ADV7183_FREE_LINE_LEN 0x8F /* Free-Run line length 1 */
|
||||
#define ADV7183_VBI_INFO 0x90 /* VBI info */
|
||||
#define ADV7183_WSS_1 0x91 /* WSS 1 */
|
||||
#define ADV7183_WSS_2 0x92 /* WSS 2 */
|
||||
#define ADV7183_EDTV_1 0x93 /* EDTV 1 */
|
||||
#define ADV7183_EDTV_2 0x94 /* EDTV 2 */
|
||||
#define ADV7183_EDTV_3 0x95 /* EDTV 3 */
|
||||
#define ADV7183_CGMS_1 0x96 /* CGMS 1 */
|
||||
#define ADV7183_CGMS_2 0x97 /* CGMS 2 */
|
||||
#define ADV7183_CGMS_3 0x98 /* CGMS 3 */
|
||||
#define ADV7183_CCAP_1 0x99 /* CCAP 1 */
|
||||
#define ADV7183_CCAP_2 0x9A /* CCAP 2 */
|
||||
#define ADV7183_LETTERBOX_1 0x9B /* Letterbox 1 */
|
||||
#define ADV7183_LETTERBOX_2 0x9C /* Letterbox 2 */
|
||||
#define ADV7183_LETTERBOX_3 0x9D /* Letterbox 3 */
|
||||
#define ADV7183_CRC_EN 0xB2 /* CRC enable */
|
||||
#define ADV7183_ADC_SWITCH_1 0xC3 /* ADC switch 1 */
|
||||
#define ADV7183_ADC_SWITCH_2 0xC4 /* ADC swithc 2 */
|
||||
#define ADV7183_LETTERBOX_CTRL_1 0xDC /* Letterbox control 1 */
|
||||
#define ADV7183_LETTERBOX_CTRL_2 0xDD /* Letterbox control 2 */
|
||||
#define ADV7183_SD_OFFSET_CB 0xE1 /* SD offset Cb */
|
||||
#define ADV7183_SD_OFFSET_CR 0xE2 /* SD offset Cr */
|
||||
#define ADV7183_SD_SATURATION_CB 0xE3 /* SD saturation Cb */
|
||||
#define ADV7183_SD_SATURATION_CR 0xE4 /* SD saturation Cr */
|
||||
#define ADV7183_NTSC_V_BEGIN 0xE5 /* NTSC V bit begin */
|
||||
#define ADV7183_NTSC_V_END 0xE6 /* NTSC V bit end */
|
||||
#define ADV7183_NTSC_F_TOGGLE 0xE7 /* NTSC F bit toggle */
|
||||
#define ADV7183_PAL_V_BEGIN 0xE8 /* PAL V bit begin */
|
||||
#define ADV7183_PAL_V_END 0xE9 /* PAL V bit end */
|
||||
#define ADV7183_PAL_F_TOGGLE 0xEA /* PAL F bit toggle */
|
||||
#define ADV7183_DRIVE_STR 0xF4 /* Drive strength */
|
||||
#define ADV7183_IF_COMP_CTRL 0xF8 /* IF comp control */
|
||||
#define ADV7183_VS_MODE_CTRL 0xF9 /* VS mode control */
|
||||
|
||||
#endif
|
||||
476
drivers/media/i2c/adv7343.c
Normal file
476
drivers/media/i2c/adv7343.c
Normal file
|
|
@ -0,0 +1,476 @@
|
|||
/*
|
||||
* adv7343 - ADV7343 Video Encoder Driver
|
||||
*
|
||||
* The encoder hardware does not support SECAM.
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed .as is. WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <media/adv7343.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
|
||||
#include "adv7343_regs.h"
|
||||
|
||||
MODULE_DESCRIPTION("ADV7343 video encoder driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Debug level 0-1");
|
||||
|
||||
struct adv7343_state {
|
||||
struct v4l2_subdev sd;
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
u8 reg00;
|
||||
u8 reg01;
|
||||
u8 reg02;
|
||||
u8 reg35;
|
||||
u8 reg80;
|
||||
u8 reg82;
|
||||
u32 output;
|
||||
v4l2_std_id std;
|
||||
};
|
||||
|
||||
static inline struct adv7343_state *to_state(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct adv7343_state, sd);
|
||||
}
|
||||
|
||||
static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd;
|
||||
}
|
||||
|
||||
static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static const u8 adv7343_init_reg_val[] = {
|
||||
ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT,
|
||||
ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT,
|
||||
|
||||
ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT,
|
||||
ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT,
|
||||
ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT,
|
||||
ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT,
|
||||
ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT,
|
||||
ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT,
|
||||
ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT,
|
||||
|
||||
ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT,
|
||||
ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT,
|
||||
ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT,
|
||||
ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT,
|
||||
ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT,
|
||||
ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT,
|
||||
ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT,
|
||||
ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT,
|
||||
|
||||
ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT,
|
||||
ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT,
|
||||
ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT,
|
||||
};
|
||||
|
||||
/*
|
||||
* 2^32
|
||||
* FSC(reg) = FSC (HZ) * --------
|
||||
* 27000000
|
||||
*/
|
||||
static const struct adv7343_std_info stdinfo[] = {
|
||||
{
|
||||
/* FSC(Hz) = 3,579,545.45 Hz */
|
||||
SD_STD_NTSC, 569408542, V4L2_STD_NTSC,
|
||||
}, {
|
||||
/* FSC(Hz) = 3,575,611.00 Hz */
|
||||
SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,
|
||||
}, {
|
||||
/* FSC(Hz) = 3,582,056.00 */
|
||||
SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,
|
||||
}, {
|
||||
/* FSC(Hz) = 4,433,618.75 Hz */
|
||||
SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,
|
||||
}, {
|
||||
/* FSC(Hz) = 4,433,618.75 Hz */
|
||||
SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,
|
||||
}, {
|
||||
/* FSC(Hz) = 4,433,618.75 Hz */
|
||||
SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,
|
||||
}, {
|
||||
/* FSC(Hz) = 4,433,618.75 Hz */
|
||||
SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,
|
||||
},
|
||||
};
|
||||
|
||||
static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct adv7343_state *state = to_state(sd);
|
||||
struct adv7343_std_info *std_info;
|
||||
int num_std;
|
||||
char *fsc_ptr;
|
||||
u8 reg, val;
|
||||
int err = 0;
|
||||
int i = 0;
|
||||
|
||||
std_info = (struct adv7343_std_info *)stdinfo;
|
||||
num_std = ARRAY_SIZE(stdinfo);
|
||||
|
||||
for (i = 0; i < num_std; i++) {
|
||||
if (std_info[i].stdid & std)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == num_std) {
|
||||
v4l2_dbg(1, debug, sd,
|
||||
"Invalid std or std is not supported: %llx\n",
|
||||
(unsigned long long)std);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set the standard */
|
||||
val = state->reg80 & (~(SD_STD_MASK));
|
||||
val |= std_info[i].standard_val3;
|
||||
err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
|
||||
if (err < 0)
|
||||
goto setstd_exit;
|
||||
|
||||
state->reg80 = val;
|
||||
|
||||
/* Configure the input mode register */
|
||||
val = state->reg01 & (~((u8) INPUT_MODE_MASK));
|
||||
val |= SD_INPUT_MODE;
|
||||
err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val);
|
||||
if (err < 0)
|
||||
goto setstd_exit;
|
||||
|
||||
state->reg01 = val;
|
||||
|
||||
/* Program the sub carrier frequency registers */
|
||||
fsc_ptr = (unsigned char *)&std_info[i].fsc_val;
|
||||
reg = ADV7343_FSC_REG0;
|
||||
for (i = 0; i < 4; i++, reg++, fsc_ptr++) {
|
||||
err = adv7343_write(sd, reg, *fsc_ptr);
|
||||
if (err < 0)
|
||||
goto setstd_exit;
|
||||
}
|
||||
|
||||
val = state->reg80;
|
||||
|
||||
/* Filter settings */
|
||||
if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))
|
||||
val &= 0x03;
|
||||
else if (std & ~V4L2_STD_SECAM)
|
||||
val |= 0x04;
|
||||
|
||||
err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
|
||||
if (err < 0)
|
||||
goto setstd_exit;
|
||||
|
||||
state->reg80 = val;
|
||||
|
||||
setstd_exit:
|
||||
if (err != 0)
|
||||
v4l2_err(sd, "Error setting std, write failed\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
|
||||
{
|
||||
struct adv7343_state *state = to_state(sd);
|
||||
unsigned char val;
|
||||
int err = 0;
|
||||
|
||||
if (output_type > ADV7343_SVIDEO_ID) {
|
||||
v4l2_dbg(1, debug, sd,
|
||||
"Invalid output type or output type not supported:%d\n",
|
||||
output_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Enable Appropriate DAC */
|
||||
val = state->reg00 & 0x03;
|
||||
|
||||
if (output_type == ADV7343_COMPOSITE_ID)
|
||||
val |= ADV7343_COMPOSITE_POWER_VALUE;
|
||||
else if (output_type == ADV7343_COMPONENT_ID)
|
||||
val |= ADV7343_COMPONENT_POWER_VALUE;
|
||||
else
|
||||
val |= ADV7343_SVIDEO_POWER_VALUE;
|
||||
|
||||
err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);
|
||||
if (err < 0)
|
||||
goto setoutput_exit;
|
||||
|
||||
state->reg00 = val;
|
||||
|
||||
/* Enable YUV output */
|
||||
val = state->reg02 | YUV_OUTPUT_SELECT;
|
||||
err = adv7343_write(sd, ADV7343_MODE_REG0, val);
|
||||
if (err < 0)
|
||||
goto setoutput_exit;
|
||||
|
||||
state->reg02 = val;
|
||||
|
||||
/* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */
|
||||
val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);
|
||||
err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);
|
||||
if (err < 0)
|
||||
goto setoutput_exit;
|
||||
|
||||
state->reg82 = val;
|
||||
|
||||
/* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to
|
||||
* zero */
|
||||
val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI);
|
||||
err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val);
|
||||
if (err < 0)
|
||||
goto setoutput_exit;
|
||||
|
||||
state->reg35 = val;
|
||||
|
||||
setoutput_exit:
|
||||
if (err != 0)
|
||||
v4l2_err(sd, "Error setting output, write failed\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7343_log_status(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct adv7343_state *state = to_state(sd);
|
||||
|
||||
v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);
|
||||
v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :
|
||||
((state->output == 1) ? "Component" : "S-Video"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct v4l2_subdev *sd = to_sd(ctrl);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_BRIGHTNESS:
|
||||
return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
|
||||
ctrl->val);
|
||||
|
||||
case V4L2_CID_HUE:
|
||||
return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val);
|
||||
|
||||
case V4L2_CID_GAIN:
|
||||
return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
|
||||
struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0);
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops adv7343_ctrl_ops = {
|
||||
.s_ctrl = adv7343_s_ctrl,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops adv7343_core_ops = {
|
||||
.log_status = adv7343_log_status,
|
||||
.g_chip_ident = adv7343_g_chip_ident,
|
||||
.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,
|
||||
};
|
||||
|
||||
static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct adv7343_state *state = to_state(sd);
|
||||
int err = 0;
|
||||
|
||||
if (state->std == std)
|
||||
return 0;
|
||||
|
||||
err = adv7343_setstd(sd, std);
|
||||
if (!err)
|
||||
state->std = std;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7343_s_routing(struct v4l2_subdev *sd,
|
||||
u32 input, u32 output, u32 config)
|
||||
{
|
||||
struct adv7343_state *state = to_state(sd);
|
||||
int err = 0;
|
||||
|
||||
if (state->output == output)
|
||||
return 0;
|
||||
|
||||
err = adv7343_setoutput(sd, output);
|
||||
if (!err)
|
||||
state->output = output;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops adv7343_video_ops = {
|
||||
.s_std_output = adv7343_s_std_output,
|
||||
.s_routing = adv7343_s_routing,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops adv7343_ops = {
|
||||
.core = &adv7343_core_ops,
|
||||
.video = &adv7343_video_ops,
|
||||
};
|
||||
|
||||
static int adv7343_initialize(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct adv7343_state *state = to_state(sd);
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) {
|
||||
|
||||
err = adv7343_write(sd, adv7343_init_reg_val[i],
|
||||
adv7343_init_reg_val[i+1]);
|
||||
if (err) {
|
||||
v4l2_err(sd, "Error initializing\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure for default video standard */
|
||||
err = adv7343_setoutput(sd, state->output);
|
||||
if (err < 0) {
|
||||
v4l2_err(sd, "Error setting output during init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = adv7343_setstd(sd, state->std);
|
||||
if (err < 0) {
|
||||
v4l2_err(sd, "Error setting std during init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7343_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adv7343_state *state;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
state->reg00 = 0x80;
|
||||
state->reg01 = 0x00;
|
||||
state->reg02 = 0x20;
|
||||
state->reg35 = 0x00;
|
||||
state->reg80 = ADV7343_SD_MODE_REG1_DEFAULT;
|
||||
state->reg82 = ADV7343_SD_MODE_REG2_DEFAULT;
|
||||
|
||||
state->output = ADV7343_COMPOSITE_ID;
|
||||
state->std = V4L2_STD_NTSC;
|
||||
|
||||
v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops);
|
||||
|
||||
v4l2_ctrl_handler_init(&state->hdl, 2);
|
||||
v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
|
||||
V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN,
|
||||
ADV7343_BRIGHTNESS_MAX, 1,
|
||||
ADV7343_BRIGHTNESS_DEF);
|
||||
v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
|
||||
V4L2_CID_HUE, ADV7343_HUE_MIN,
|
||||
ADV7343_HUE_MAX, 1,
|
||||
ADV7343_HUE_DEF);
|
||||
v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
|
||||
V4L2_CID_GAIN, ADV7343_GAIN_MIN,
|
||||
ADV7343_GAIN_MAX, 1,
|
||||
ADV7343_GAIN_DEF);
|
||||
state->sd.ctrl_handler = &state->hdl;
|
||||
if (state->hdl.error) {
|
||||
int err = state->hdl.error;
|
||||
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
kfree(state);
|
||||
return err;
|
||||
}
|
||||
v4l2_ctrl_handler_setup(&state->hdl);
|
||||
|
||||
err = adv7343_initialize(&state->sd);
|
||||
if (err) {
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
kfree(state);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7343_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct adv7343_state *state = to_state(sd);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
kfree(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adv7343_id[] = {
|
||||
{"adv7343", 0},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, adv7343_id);
|
||||
|
||||
static struct i2c_driver adv7343_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "adv7343",
|
||||
},
|
||||
.probe = adv7343_probe,
|
||||
.remove = adv7343_remove,
|
||||
.id_table = adv7343_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(adv7343_driver);
|
||||
181
drivers/media/i2c/adv7343_regs.h
Normal file
181
drivers/media/i2c/adv7343_regs.h
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* ADV7343 encoder related structure and register definitions
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed .as is. WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef ADV7343_REG_H
|
||||
#define ADV7343_REGS_H
|
||||
|
||||
struct adv7343_std_info {
|
||||
u32 standard_val3;
|
||||
u32 fsc_val;
|
||||
v4l2_std_id stdid;
|
||||
};
|
||||
|
||||
/* Register offset macros */
|
||||
#define ADV7343_POWER_MODE_REG (0x00)
|
||||
#define ADV7343_MODE_SELECT_REG (0x01)
|
||||
#define ADV7343_MODE_REG0 (0x02)
|
||||
|
||||
#define ADV7343_DAC2_OUTPUT_LEVEL (0x0b)
|
||||
|
||||
#define ADV7343_SOFT_RESET (0x17)
|
||||
|
||||
#define ADV7343_HD_MODE_REG1 (0x30)
|
||||
#define ADV7343_HD_MODE_REG2 (0x31)
|
||||
#define ADV7343_HD_MODE_REG3 (0x32)
|
||||
#define ADV7343_HD_MODE_REG4 (0x33)
|
||||
#define ADV7343_HD_MODE_REG5 (0x34)
|
||||
#define ADV7343_HD_MODE_REG6 (0x35)
|
||||
|
||||
#define ADV7343_HD_MODE_REG7 (0x39)
|
||||
|
||||
#define ADV7343_SD_MODE_REG1 (0x80)
|
||||
#define ADV7343_SD_MODE_REG2 (0x82)
|
||||
#define ADV7343_SD_MODE_REG3 (0x83)
|
||||
#define ADV7343_SD_MODE_REG4 (0x84)
|
||||
#define ADV7343_SD_MODE_REG5 (0x86)
|
||||
#define ADV7343_SD_MODE_REG6 (0x87)
|
||||
#define ADV7343_SD_MODE_REG7 (0x88)
|
||||
#define ADV7343_SD_MODE_REG8 (0x89)
|
||||
|
||||
#define ADV7343_FSC_REG0 (0x8C)
|
||||
#define ADV7343_FSC_REG1 (0x8D)
|
||||
#define ADV7343_FSC_REG2 (0x8E)
|
||||
#define ADV7343_FSC_REG3 (0x8F)
|
||||
|
||||
#define ADV7343_SD_CGMS_WSS0 (0x99)
|
||||
|
||||
#define ADV7343_SD_HUE_REG (0xA0)
|
||||
#define ADV7343_SD_BRIGHTNESS_WSS (0xA1)
|
||||
|
||||
/* Default values for the registers */
|
||||
#define ADV7343_POWER_MODE_REG_DEFAULT (0x10)
|
||||
#define ADV7343_HD_MODE_REG1_DEFAULT (0x3C) /* Changed Default
|
||||
720p EAVSAV code*/
|
||||
#define ADV7343_HD_MODE_REG2_DEFAULT (0x01) /* Changed Pixel data
|
||||
valid */
|
||||
#define ADV7343_HD_MODE_REG3_DEFAULT (0x00) /* Color delay 0 clks */
|
||||
#define ADV7343_HD_MODE_REG4_DEFAULT (0xE8) /* Changed */
|
||||
#define ADV7343_HD_MODE_REG5_DEFAULT (0x08)
|
||||
#define ADV7343_HD_MODE_REG6_DEFAULT (0x00)
|
||||
#define ADV7343_HD_MODE_REG7_DEFAULT (0x00)
|
||||
#define ADV7343_SD_MODE_REG8_DEFAULT (0x00)
|
||||
#define ADV7343_SOFT_RESET_DEFAULT (0x02)
|
||||
#define ADV7343_COMPOSITE_POWER_VALUE (0x80)
|
||||
#define ADV7343_COMPONENT_POWER_VALUE (0x1C)
|
||||
#define ADV7343_SVIDEO_POWER_VALUE (0x60)
|
||||
#define ADV7343_SD_HUE_REG_DEFAULT (127)
|
||||
#define ADV7343_SD_BRIGHTNESS_WSS_DEFAULT (0x03)
|
||||
|
||||
#define ADV7343_SD_CGMS_WSS0_DEFAULT (0x10)
|
||||
|
||||
#define ADV7343_SD_MODE_REG1_DEFAULT (0x00)
|
||||
#define ADV7343_SD_MODE_REG2_DEFAULT (0xC9)
|
||||
#define ADV7343_SD_MODE_REG3_DEFAULT (0x10)
|
||||
#define ADV7343_SD_MODE_REG4_DEFAULT (0x01)
|
||||
#define ADV7343_SD_MODE_REG5_DEFAULT (0x02)
|
||||
#define ADV7343_SD_MODE_REG6_DEFAULT (0x0C)
|
||||
#define ADV7343_SD_MODE_REG7_DEFAULT (0x04)
|
||||
#define ADV7343_SD_MODE_REG8_DEFAULT (0x00)
|
||||
|
||||
/* Bit masks for Mode Select Register */
|
||||
#define INPUT_MODE_MASK (0x70)
|
||||
#define SD_INPUT_MODE (0x00)
|
||||
#define HD_720P_INPUT_MODE (0x10)
|
||||
#define HD_1080I_INPUT_MODE (0x10)
|
||||
|
||||
/* Bit masks for Mode Register 0 */
|
||||
#define TEST_PATTERN_BLACK_BAR_EN (0x04)
|
||||
#define YUV_OUTPUT_SELECT (0x20)
|
||||
#define RGB_OUTPUT_SELECT (0xDF)
|
||||
|
||||
/* Bit masks for DAC output levels */
|
||||
#define DAC_OUTPUT_LEVEL_MASK (0xFF)
|
||||
|
||||
/* Bit masks for soft reset register */
|
||||
#define SOFT_RESET (0x02)
|
||||
|
||||
/* Bit masks for HD Mode Register 1 */
|
||||
#define OUTPUT_STD_MASK (0x03)
|
||||
#define OUTPUT_STD_SHIFT (0)
|
||||
#define OUTPUT_STD_EIA0_2 (0x00)
|
||||
#define OUTPUT_STD_EIA0_1 (0x01)
|
||||
#define OUTPUT_STD_FULL (0x02)
|
||||
#define EMBEDDED_SYNC (0x04)
|
||||
#define EXTERNAL_SYNC (0xFB)
|
||||
#define STD_MODE_SHIFT (3)
|
||||
#define STD_MODE_MASK (0x1F)
|
||||
#define STD_MODE_720P (0x05)
|
||||
#define STD_MODE_720P_25 (0x08)
|
||||
#define STD_MODE_720P_30 (0x07)
|
||||
#define STD_MODE_720P_50 (0x06)
|
||||
#define STD_MODE_1080I (0x0D)
|
||||
#define STD_MODE_1080I_25fps (0x0E)
|
||||
#define STD_MODE_1080P_24 (0x12)
|
||||
#define STD_MODE_1080P_25 (0x10)
|
||||
#define STD_MODE_1080P_30 (0x0F)
|
||||
#define STD_MODE_525P (0x00)
|
||||
#define STD_MODE_625P (0x03)
|
||||
|
||||
/* Bit masks for SD Mode Register 1 */
|
||||
#define SD_STD_MASK (0x03)
|
||||
#define SD_STD_NTSC (0x00)
|
||||
#define SD_STD_PAL_BDGHI (0x01)
|
||||
#define SD_STD_PAL_M (0x02)
|
||||
#define SD_STD_PAL_N (0x03)
|
||||
#define SD_LUMA_FLTR_MASK (0x7)
|
||||
#define SD_LUMA_FLTR_SHIFT (0x2)
|
||||
#define SD_CHROMA_FLTR_MASK (0x7)
|
||||
#define SD_CHROMA_FLTR_SHIFT (0x5)
|
||||
|
||||
/* Bit masks for SD Mode Register 2 */
|
||||
#define SD_PBPR_SSAF_EN (0x01)
|
||||
#define SD_PBPR_SSAF_DI (0xFE)
|
||||
#define SD_DAC_1_DI (0xFD)
|
||||
#define SD_DAC_2_DI (0xFB)
|
||||
#define SD_PEDESTAL_EN (0x08)
|
||||
#define SD_PEDESTAL_DI (0xF7)
|
||||
#define SD_SQUARE_PIXEL_EN (0x10)
|
||||
#define SD_SQUARE_PIXEL_DI (0xEF)
|
||||
#define SD_PIXEL_DATA_VALID (0x40)
|
||||
#define SD_ACTIVE_EDGE_EN (0x80)
|
||||
#define SD_ACTIVE_EDGE_DI (0x7F)
|
||||
|
||||
/* Bit masks for HD Mode Register 6 */
|
||||
#define HD_RGB_INPUT_EN (0x02)
|
||||
#define HD_RGB_INPUT_DI (0xFD)
|
||||
#define HD_PBPR_SYNC_EN (0x04)
|
||||
#define HD_PBPR_SYNC_DI (0xFB)
|
||||
#define HD_DAC_SWAP_EN (0x08)
|
||||
#define HD_DAC_SWAP_DI (0xF7)
|
||||
#define HD_GAMMA_CURVE_A (0xEF)
|
||||
#define HD_GAMMA_CURVE_B (0x10)
|
||||
#define HD_GAMMA_EN (0x20)
|
||||
#define HD_GAMMA_DI (0xDF)
|
||||
#define HD_ADPT_FLTR_MODEB (0x40)
|
||||
#define HD_ADPT_FLTR_MODEA (0xBF)
|
||||
#define HD_ADPT_FLTR_EN (0x80)
|
||||
#define HD_ADPT_FLTR_DI (0x7F)
|
||||
|
||||
#define ADV7343_BRIGHTNESS_MAX (127)
|
||||
#define ADV7343_BRIGHTNESS_MIN (0)
|
||||
#define ADV7343_BRIGHTNESS_DEF (3)
|
||||
#define ADV7343_HUE_MAX (255)
|
||||
#define ADV7343_HUE_MIN (0)
|
||||
#define ADV7343_HUE_DEF (127)
|
||||
#define ADV7343_GAIN_MAX (64)
|
||||
#define ADV7343_GAIN_MIN (-64)
|
||||
#define ADV7343_GAIN_DEF (0)
|
||||
|
||||
#endif
|
||||
487
drivers/media/i2c/adv7393.c
Normal file
487
drivers/media/i2c/adv7393.c
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
/*
|
||||
* adv7393 - ADV7393 Video Encoder Driver
|
||||
*
|
||||
* The encoder hardware does not support SECAM.
|
||||
*
|
||||
* Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/
|
||||
* Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
|
||||
*
|
||||
* Based on ADV7343 driver,
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed .as is. WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <media/adv7393.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
|
||||
#include "adv7393_regs.h"
|
||||
|
||||
MODULE_DESCRIPTION("ADV7393 video encoder driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static bool debug;
|
||||
module_param(debug, bool, 0644);
|
||||
MODULE_PARM_DESC(debug, "Debug level 0-1");
|
||||
|
||||
struct adv7393_state {
|
||||
struct v4l2_subdev sd;
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
u8 reg00;
|
||||
u8 reg01;
|
||||
u8 reg02;
|
||||
u8 reg35;
|
||||
u8 reg80;
|
||||
u8 reg82;
|
||||
u32 output;
|
||||
v4l2_std_id std;
|
||||
};
|
||||
|
||||
static inline struct adv7393_state *to_state(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct adv7393_state, sd);
|
||||
}
|
||||
|
||||
static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
return &container_of(ctrl->handler, struct adv7393_state, hdl)->sd;
|
||||
}
|
||||
|
||||
static inline int adv7393_write(struct v4l2_subdev *sd, u8 reg, u8 value)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static const u8 adv7393_init_reg_val[] = {
|
||||
ADV7393_SOFT_RESET, ADV7393_SOFT_RESET_DEFAULT,
|
||||
ADV7393_POWER_MODE_REG, ADV7393_POWER_MODE_REG_DEFAULT,
|
||||
|
||||
ADV7393_HD_MODE_REG1, ADV7393_HD_MODE_REG1_DEFAULT,
|
||||
ADV7393_HD_MODE_REG2, ADV7393_HD_MODE_REG2_DEFAULT,
|
||||
ADV7393_HD_MODE_REG3, ADV7393_HD_MODE_REG3_DEFAULT,
|
||||
ADV7393_HD_MODE_REG4, ADV7393_HD_MODE_REG4_DEFAULT,
|
||||
ADV7393_HD_MODE_REG5, ADV7393_HD_MODE_REG5_DEFAULT,
|
||||
ADV7393_HD_MODE_REG6, ADV7393_HD_MODE_REG6_DEFAULT,
|
||||
ADV7393_HD_MODE_REG7, ADV7393_HD_MODE_REG7_DEFAULT,
|
||||
|
||||
ADV7393_SD_MODE_REG1, ADV7393_SD_MODE_REG1_DEFAULT,
|
||||
ADV7393_SD_MODE_REG2, ADV7393_SD_MODE_REG2_DEFAULT,
|
||||
ADV7393_SD_MODE_REG3, ADV7393_SD_MODE_REG3_DEFAULT,
|
||||
ADV7393_SD_MODE_REG4, ADV7393_SD_MODE_REG4_DEFAULT,
|
||||
ADV7393_SD_MODE_REG5, ADV7393_SD_MODE_REG5_DEFAULT,
|
||||
ADV7393_SD_MODE_REG6, ADV7393_SD_MODE_REG6_DEFAULT,
|
||||
ADV7393_SD_MODE_REG7, ADV7393_SD_MODE_REG7_DEFAULT,
|
||||
ADV7393_SD_MODE_REG8, ADV7393_SD_MODE_REG8_DEFAULT,
|
||||
|
||||
ADV7393_SD_TIMING_REG0, ADV7393_SD_TIMING_REG0_DEFAULT,
|
||||
|
||||
ADV7393_SD_HUE_ADJUST, ADV7393_SD_HUE_ADJUST_DEFAULT,
|
||||
ADV7393_SD_CGMS_WSS0, ADV7393_SD_CGMS_WSS0_DEFAULT,
|
||||
ADV7393_SD_BRIGHTNESS_WSS, ADV7393_SD_BRIGHTNESS_WSS_DEFAULT,
|
||||
};
|
||||
|
||||
/*
|
||||
* 2^32
|
||||
* FSC(reg) = FSC (HZ) * --------
|
||||
* 27000000
|
||||
*/
|
||||
static const struct adv7393_std_info stdinfo[] = {
|
||||
{
|
||||
/* FSC(Hz) = 4,433,618.75 Hz */
|
||||
SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,
|
||||
}, {
|
||||
/* FSC(Hz) = 3,579,545.45 Hz */
|
||||
SD_STD_NTSC, 569408542, V4L2_STD_NTSC,
|
||||
}, {
|
||||
/* FSC(Hz) = 3,575,611.00 Hz */
|
||||
SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,
|
||||
}, {
|
||||
/* FSC(Hz) = 3,582,056.00 Hz */
|
||||
SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,
|
||||
}, {
|
||||
/* FSC(Hz) = 4,433,618.75 Hz */
|
||||
SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,
|
||||
}, {
|
||||
/* FSC(Hz) = 4,433,618.75 Hz */
|
||||
SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,
|
||||
}, {
|
||||
/* FSC(Hz) = 4,433,618.75 Hz */
|
||||
SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,
|
||||
},
|
||||
};
|
||||
|
||||
static int adv7393_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct adv7393_state *state = to_state(sd);
|
||||
const struct adv7393_std_info *std_info;
|
||||
int num_std;
|
||||
u8 reg;
|
||||
u32 val;
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
num_std = ARRAY_SIZE(stdinfo);
|
||||
|
||||
for (i = 0; i < num_std; i++) {
|
||||
if (stdinfo[i].stdid & std)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == num_std) {
|
||||
v4l2_dbg(1, debug, sd,
|
||||
"Invalid std or std is not supported: %llx\n",
|
||||
(unsigned long long)std);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
std_info = &stdinfo[i];
|
||||
|
||||
/* Set the standard */
|
||||
val = state->reg80 & ~SD_STD_MASK;
|
||||
val |= std_info->standard_val3;
|
||||
err = adv7393_write(sd, ADV7393_SD_MODE_REG1, val);
|
||||
if (err < 0)
|
||||
goto setstd_exit;
|
||||
|
||||
state->reg80 = val;
|
||||
|
||||
/* Configure the input mode register */
|
||||
val = state->reg01 & ~INPUT_MODE_MASK;
|
||||
val |= SD_INPUT_MODE;
|
||||
err = adv7393_write(sd, ADV7393_MODE_SELECT_REG, val);
|
||||
if (err < 0)
|
||||
goto setstd_exit;
|
||||
|
||||
state->reg01 = val;
|
||||
|
||||
/* Program the sub carrier frequency registers */
|
||||
val = std_info->fsc_val;
|
||||
for (reg = ADV7393_FSC_REG0; reg <= ADV7393_FSC_REG3; reg++) {
|
||||
err = adv7393_write(sd, reg, val);
|
||||
if (err < 0)
|
||||
goto setstd_exit;
|
||||
val >>= 8;
|
||||
}
|
||||
|
||||
val = state->reg82;
|
||||
|
||||
/* Pedestal settings */
|
||||
if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))
|
||||
val |= SD_PEDESTAL_EN;
|
||||
else
|
||||
val &= SD_PEDESTAL_DI;
|
||||
|
||||
err = adv7393_write(sd, ADV7393_SD_MODE_REG2, val);
|
||||
if (err < 0)
|
||||
goto setstd_exit;
|
||||
|
||||
state->reg82 = val;
|
||||
|
||||
setstd_exit:
|
||||
if (err != 0)
|
||||
v4l2_err(sd, "Error setting std, write failed\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7393_setoutput(struct v4l2_subdev *sd, u32 output_type)
|
||||
{
|
||||
struct adv7393_state *state = to_state(sd);
|
||||
u8 val;
|
||||
int err = 0;
|
||||
|
||||
if (output_type > ADV7393_SVIDEO_ID) {
|
||||
v4l2_dbg(1, debug, sd,
|
||||
"Invalid output type or output type not supported:%d\n",
|
||||
output_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Enable Appropriate DAC */
|
||||
val = state->reg00 & 0x03;
|
||||
|
||||
if (output_type == ADV7393_COMPOSITE_ID)
|
||||
val |= ADV7393_COMPOSITE_POWER_VALUE;
|
||||
else if (output_type == ADV7393_COMPONENT_ID)
|
||||
val |= ADV7393_COMPONENT_POWER_VALUE;
|
||||
else
|
||||
val |= ADV7393_SVIDEO_POWER_VALUE;
|
||||
|
||||
err = adv7393_write(sd, ADV7393_POWER_MODE_REG, val);
|
||||
if (err < 0)
|
||||
goto setoutput_exit;
|
||||
|
||||
state->reg00 = val;
|
||||
|
||||
/* Enable YUV output */
|
||||
val = state->reg02 | YUV_OUTPUT_SELECT;
|
||||
err = adv7393_write(sd, ADV7393_MODE_REG0, val);
|
||||
if (err < 0)
|
||||
goto setoutput_exit;
|
||||
|
||||
state->reg02 = val;
|
||||
|
||||
/* configure SD DAC Output 1 bit */
|
||||
val = state->reg82;
|
||||
if (output_type == ADV7393_COMPONENT_ID)
|
||||
val &= SD_DAC_OUT1_DI;
|
||||
else
|
||||
val |= SD_DAC_OUT1_EN;
|
||||
err = adv7393_write(sd, ADV7393_SD_MODE_REG2, val);
|
||||
if (err < 0)
|
||||
goto setoutput_exit;
|
||||
|
||||
state->reg82 = val;
|
||||
|
||||
/* configure ED/HD Color DAC Swap bit to zero */
|
||||
val = state->reg35 & HD_DAC_SWAP_DI;
|
||||
err = adv7393_write(sd, ADV7393_HD_MODE_REG6, val);
|
||||
if (err < 0)
|
||||
goto setoutput_exit;
|
||||
|
||||
state->reg35 = val;
|
||||
|
||||
setoutput_exit:
|
||||
if (err != 0)
|
||||
v4l2_err(sd, "Error setting output, write failed\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7393_log_status(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct adv7393_state *state = to_state(sd);
|
||||
|
||||
v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);
|
||||
v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :
|
||||
((state->output == 1) ? "Component" : "S-Video"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7393_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct v4l2_subdev *sd = to_sd(ctrl);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_BRIGHTNESS:
|
||||
return adv7393_write(sd, ADV7393_SD_BRIGHTNESS_WSS,
|
||||
ctrl->val & SD_BRIGHTNESS_VALUE_MASK);
|
||||
|
||||
case V4L2_CID_HUE:
|
||||
return adv7393_write(sd, ADV7393_SD_HUE_ADJUST,
|
||||
ctrl->val - ADV7393_HUE_MIN);
|
||||
|
||||
case V4L2_CID_GAIN:
|
||||
return adv7393_write(sd, ADV7393_DAC123_OUTPUT_LEVEL,
|
||||
ctrl->val);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adv7393_g_chip_ident(struct v4l2_subdev *sd,
|
||||
struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7393, 0);
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops adv7393_ctrl_ops = {
|
||||
.s_ctrl = adv7393_s_ctrl,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops adv7393_core_ops = {
|
||||
.log_status = adv7393_log_status,
|
||||
.g_chip_ident = adv7393_g_chip_ident,
|
||||
.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,
|
||||
};
|
||||
|
||||
static int adv7393_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct adv7393_state *state = to_state(sd);
|
||||
int err = 0;
|
||||
|
||||
if (state->std == std)
|
||||
return 0;
|
||||
|
||||
err = adv7393_setstd(sd, std);
|
||||
if (!err)
|
||||
state->std = std;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7393_s_routing(struct v4l2_subdev *sd,
|
||||
u32 input, u32 output, u32 config)
|
||||
{
|
||||
struct adv7393_state *state = to_state(sd);
|
||||
int err = 0;
|
||||
|
||||
if (state->output == output)
|
||||
return 0;
|
||||
|
||||
err = adv7393_setoutput(sd, output);
|
||||
if (!err)
|
||||
state->output = output;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops adv7393_video_ops = {
|
||||
.s_std_output = adv7393_s_std_output,
|
||||
.s_routing = adv7393_s_routing,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops adv7393_ops = {
|
||||
.core = &adv7393_core_ops,
|
||||
.video = &adv7393_video_ops,
|
||||
};
|
||||
|
||||
static int adv7393_initialize(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct adv7393_state *state = to_state(sd);
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(adv7393_init_reg_val); i += 2) {
|
||||
|
||||
err = adv7393_write(sd, adv7393_init_reg_val[i],
|
||||
adv7393_init_reg_val[i+1]);
|
||||
if (err) {
|
||||
v4l2_err(sd, "Error initializing\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Configure for default video standard */
|
||||
err = adv7393_setoutput(sd, state->output);
|
||||
if (err < 0) {
|
||||
v4l2_err(sd, "Error setting output during init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = adv7393_setstd(sd, state->std);
|
||||
if (err < 0) {
|
||||
v4l2_err(sd, "Error setting std during init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7393_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct adv7393_state *state;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
state = kzalloc(sizeof(struct adv7393_state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
state->reg00 = ADV7393_POWER_MODE_REG_DEFAULT;
|
||||
state->reg01 = 0x00;
|
||||
state->reg02 = 0x20;
|
||||
state->reg35 = ADV7393_HD_MODE_REG6_DEFAULT;
|
||||
state->reg80 = ADV7393_SD_MODE_REG1_DEFAULT;
|
||||
state->reg82 = ADV7393_SD_MODE_REG2_DEFAULT;
|
||||
|
||||
state->output = ADV7393_COMPOSITE_ID;
|
||||
state->std = V4L2_STD_NTSC;
|
||||
|
||||
v4l2_i2c_subdev_init(&state->sd, client, &adv7393_ops);
|
||||
|
||||
v4l2_ctrl_handler_init(&state->hdl, 3);
|
||||
v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops,
|
||||
V4L2_CID_BRIGHTNESS, ADV7393_BRIGHTNESS_MIN,
|
||||
ADV7393_BRIGHTNESS_MAX, 1,
|
||||
ADV7393_BRIGHTNESS_DEF);
|
||||
v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops,
|
||||
V4L2_CID_HUE, ADV7393_HUE_MIN,
|
||||
ADV7393_HUE_MAX, 1,
|
||||
ADV7393_HUE_DEF);
|
||||
v4l2_ctrl_new_std(&state->hdl, &adv7393_ctrl_ops,
|
||||
V4L2_CID_GAIN, ADV7393_GAIN_MIN,
|
||||
ADV7393_GAIN_MAX, 1,
|
||||
ADV7393_GAIN_DEF);
|
||||
state->sd.ctrl_handler = &state->hdl;
|
||||
if (state->hdl.error) {
|
||||
int err = state->hdl.error;
|
||||
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
kfree(state);
|
||||
return err;
|
||||
}
|
||||
v4l2_ctrl_handler_setup(&state->hdl);
|
||||
|
||||
err = adv7393_initialize(&state->sd);
|
||||
if (err) {
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
kfree(state);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int adv7393_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct adv7393_state *state = to_state(sd);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(&state->hdl);
|
||||
kfree(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adv7393_id[] = {
|
||||
{"adv7393", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adv7393_id);
|
||||
|
||||
static struct i2c_driver adv7393_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "adv7393",
|
||||
},
|
||||
.probe = adv7393_probe,
|
||||
.remove = adv7393_remove,
|
||||
.id_table = adv7393_id,
|
||||
};
|
||||
module_i2c_driver(adv7393_driver);
|
||||
188
drivers/media/i2c/adv7393_regs.h
Normal file
188
drivers/media/i2c/adv7393_regs.h
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* ADV7393 encoder related structure and register definitions
|
||||
*
|
||||
* Copyright (C) 2010-2012 ADVANSEE - http://www.advansee.com/
|
||||
* Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
|
||||
*
|
||||
* Based on ADV7343 driver,
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation version 2.
|
||||
*
|
||||
* This program is distributed .as is. WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef ADV7393_REGS_H
|
||||
#define ADV7393_REGS_H
|
||||
|
||||
struct adv7393_std_info {
|
||||
u32 standard_val3;
|
||||
u32 fsc_val;
|
||||
v4l2_std_id stdid;
|
||||
};
|
||||
|
||||
/* Register offset macros */
|
||||
#define ADV7393_POWER_MODE_REG (0x00)
|
||||
#define ADV7393_MODE_SELECT_REG (0x01)
|
||||
#define ADV7393_MODE_REG0 (0x02)
|
||||
|
||||
#define ADV7393_DAC123_OUTPUT_LEVEL (0x0B)
|
||||
|
||||
#define ADV7393_SOFT_RESET (0x17)
|
||||
|
||||
#define ADV7393_HD_MODE_REG1 (0x30)
|
||||
#define ADV7393_HD_MODE_REG2 (0x31)
|
||||
#define ADV7393_HD_MODE_REG3 (0x32)
|
||||
#define ADV7393_HD_MODE_REG4 (0x33)
|
||||
#define ADV7393_HD_MODE_REG5 (0x34)
|
||||
#define ADV7393_HD_MODE_REG6 (0x35)
|
||||
|
||||
#define ADV7393_HD_MODE_REG7 (0x39)
|
||||
|
||||
#define ADV7393_SD_MODE_REG1 (0x80)
|
||||
#define ADV7393_SD_MODE_REG2 (0x82)
|
||||
#define ADV7393_SD_MODE_REG3 (0x83)
|
||||
#define ADV7393_SD_MODE_REG4 (0x84)
|
||||
#define ADV7393_SD_MODE_REG5 (0x86)
|
||||
#define ADV7393_SD_MODE_REG6 (0x87)
|
||||
#define ADV7393_SD_MODE_REG7 (0x88)
|
||||
#define ADV7393_SD_MODE_REG8 (0x89)
|
||||
|
||||
#define ADV7393_SD_TIMING_REG0 (0x8A)
|
||||
|
||||
#define ADV7393_FSC_REG0 (0x8C)
|
||||
#define ADV7393_FSC_REG1 (0x8D)
|
||||
#define ADV7393_FSC_REG2 (0x8E)
|
||||
#define ADV7393_FSC_REG3 (0x8F)
|
||||
|
||||
#define ADV7393_SD_CGMS_WSS0 (0x99)
|
||||
|
||||
#define ADV7393_SD_HUE_ADJUST (0xA0)
|
||||
#define ADV7393_SD_BRIGHTNESS_WSS (0xA1)
|
||||
|
||||
/* Default values for the registers */
|
||||
#define ADV7393_POWER_MODE_REG_DEFAULT (0x10)
|
||||
#define ADV7393_HD_MODE_REG1_DEFAULT (0x3C) /* Changed Default
|
||||
720p EAV/SAV code*/
|
||||
#define ADV7393_HD_MODE_REG2_DEFAULT (0x01) /* Changed Pixel data
|
||||
valid */
|
||||
#define ADV7393_HD_MODE_REG3_DEFAULT (0x00) /* Color delay 0 clks */
|
||||
#define ADV7393_HD_MODE_REG4_DEFAULT (0xEC) /* Changed */
|
||||
#define ADV7393_HD_MODE_REG5_DEFAULT (0x08)
|
||||
#define ADV7393_HD_MODE_REG6_DEFAULT (0x00)
|
||||
#define ADV7393_HD_MODE_REG7_DEFAULT (0x00)
|
||||
#define ADV7393_SOFT_RESET_DEFAULT (0x02)
|
||||
#define ADV7393_COMPOSITE_POWER_VALUE (0x10)
|
||||
#define ADV7393_COMPONENT_POWER_VALUE (0x1C)
|
||||
#define ADV7393_SVIDEO_POWER_VALUE (0x0C)
|
||||
#define ADV7393_SD_HUE_ADJUST_DEFAULT (0x80)
|
||||
#define ADV7393_SD_BRIGHTNESS_WSS_DEFAULT (0x00)
|
||||
|
||||
#define ADV7393_SD_CGMS_WSS0_DEFAULT (0x10)
|
||||
|
||||
#define ADV7393_SD_MODE_REG1_DEFAULT (0x10)
|
||||
#define ADV7393_SD_MODE_REG2_DEFAULT (0xC9)
|
||||
#define ADV7393_SD_MODE_REG3_DEFAULT (0x00)
|
||||
#define ADV7393_SD_MODE_REG4_DEFAULT (0x00)
|
||||
#define ADV7393_SD_MODE_REG5_DEFAULT (0x02)
|
||||
#define ADV7393_SD_MODE_REG6_DEFAULT (0x8C)
|
||||
#define ADV7393_SD_MODE_REG7_DEFAULT (0x14)
|
||||
#define ADV7393_SD_MODE_REG8_DEFAULT (0x00)
|
||||
|
||||
#define ADV7393_SD_TIMING_REG0_DEFAULT (0x0C)
|
||||
|
||||
/* Bit masks for Mode Select Register */
|
||||
#define INPUT_MODE_MASK (0x70)
|
||||
#define SD_INPUT_MODE (0x00)
|
||||
#define HD_720P_INPUT_MODE (0x10)
|
||||
#define HD_1080I_INPUT_MODE (0x10)
|
||||
|
||||
/* Bit masks for Mode Register 0 */
|
||||
#define TEST_PATTERN_BLACK_BAR_EN (0x04)
|
||||
#define YUV_OUTPUT_SELECT (0x20)
|
||||
#define RGB_OUTPUT_SELECT (0xDF)
|
||||
|
||||
/* Bit masks for SD brightness/WSS */
|
||||
#define SD_BRIGHTNESS_VALUE_MASK (0x7F)
|
||||
#define SD_BLANK_WSS_DATA_MASK (0x80)
|
||||
|
||||
/* Bit masks for soft reset register */
|
||||
#define SOFT_RESET (0x02)
|
||||
|
||||
/* Bit masks for HD Mode Register 1 */
|
||||
#define OUTPUT_STD_MASK (0x03)
|
||||
#define OUTPUT_STD_SHIFT (0)
|
||||
#define OUTPUT_STD_EIA0_2 (0x00)
|
||||
#define OUTPUT_STD_EIA0_1 (0x01)
|
||||
#define OUTPUT_STD_FULL (0x02)
|
||||
#define EMBEDDED_SYNC (0x04)
|
||||
#define EXTERNAL_SYNC (0xFB)
|
||||
#define STD_MODE_MASK (0x1F)
|
||||
#define STD_MODE_SHIFT (3)
|
||||
#define STD_MODE_720P (0x05)
|
||||
#define STD_MODE_720P_25 (0x08)
|
||||
#define STD_MODE_720P_30 (0x07)
|
||||
#define STD_MODE_720P_50 (0x06)
|
||||
#define STD_MODE_1080I (0x0D)
|
||||
#define STD_MODE_1080I_25 (0x0E)
|
||||
#define STD_MODE_1080P_24 (0x11)
|
||||
#define STD_MODE_1080P_25 (0x10)
|
||||
#define STD_MODE_1080P_30 (0x0F)
|
||||
#define STD_MODE_525P (0x00)
|
||||
#define STD_MODE_625P (0x03)
|
||||
|
||||
/* Bit masks for SD Mode Register 1 */
|
||||
#define SD_STD_MASK (0x03)
|
||||
#define SD_STD_NTSC (0x00)
|
||||
#define SD_STD_PAL_BDGHI (0x01)
|
||||
#define SD_STD_PAL_M (0x02)
|
||||
#define SD_STD_PAL_N (0x03)
|
||||
#define SD_LUMA_FLTR_MASK (0x07)
|
||||
#define SD_LUMA_FLTR_SHIFT (2)
|
||||
#define SD_CHROMA_FLTR_MASK (0x07)
|
||||
#define SD_CHROMA_FLTR_SHIFT (5)
|
||||
|
||||
/* Bit masks for SD Mode Register 2 */
|
||||
#define SD_PRPB_SSAF_EN (0x01)
|
||||
#define SD_PRPB_SSAF_DI (0xFE)
|
||||
#define SD_DAC_OUT1_EN (0x02)
|
||||
#define SD_DAC_OUT1_DI (0xFD)
|
||||
#define SD_PEDESTAL_EN (0x08)
|
||||
#define SD_PEDESTAL_DI (0xF7)
|
||||
#define SD_SQUARE_PIXEL_EN (0x10)
|
||||
#define SD_SQUARE_PIXEL_DI (0xEF)
|
||||
#define SD_PIXEL_DATA_VALID (0x40)
|
||||
#define SD_ACTIVE_EDGE_EN (0x80)
|
||||
#define SD_ACTIVE_EDGE_DI (0x7F)
|
||||
|
||||
/* Bit masks for HD Mode Register 6 */
|
||||
#define HD_PRPB_SYNC_EN (0x04)
|
||||
#define HD_PRPB_SYNC_DI (0xFB)
|
||||
#define HD_DAC_SWAP_EN (0x08)
|
||||
#define HD_DAC_SWAP_DI (0xF7)
|
||||
#define HD_GAMMA_CURVE_A (0xEF)
|
||||
#define HD_GAMMA_CURVE_B (0x10)
|
||||
#define HD_GAMMA_EN (0x20)
|
||||
#define HD_GAMMA_DI (0xDF)
|
||||
#define HD_ADPT_FLTR_MODEA (0xBF)
|
||||
#define HD_ADPT_FLTR_MODEB (0x40)
|
||||
#define HD_ADPT_FLTR_EN (0x80)
|
||||
#define HD_ADPT_FLTR_DI (0x7F)
|
||||
|
||||
#define ADV7393_BRIGHTNESS_MAX (63)
|
||||
#define ADV7393_BRIGHTNESS_MIN (-64)
|
||||
#define ADV7393_BRIGHTNESS_DEF (0)
|
||||
#define ADV7393_HUE_MAX (127)
|
||||
#define ADV7393_HUE_MIN (-128)
|
||||
#define ADV7393_HUE_DEF (0)
|
||||
#define ADV7393_GAIN_MAX (64)
|
||||
#define ADV7393_GAIN_MIN (-64)
|
||||
#define ADV7393_GAIN_DEF (0)
|
||||
|
||||
#endif
|
||||
359
drivers/media/i2c/ak881x.c
Normal file
359
drivers/media/i2c/ak881x.c
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* Driver for AK8813 / AK8814 TV-ecoders from Asahi Kasei Microsystems Co., Ltd. (AKM)
|
||||
*
|
||||
* 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/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <media/ak881x.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-device.h>
|
||||
|
||||
#define AK881X_INTERFACE_MODE 0
|
||||
#define AK881X_VIDEO_PROCESS1 1
|
||||
#define AK881X_VIDEO_PROCESS2 2
|
||||
#define AK881X_VIDEO_PROCESS3 3
|
||||
#define AK881X_DAC_MODE 5
|
||||
#define AK881X_STATUS 0x24
|
||||
#define AK881X_DEVICE_ID 0x25
|
||||
#define AK881X_DEVICE_REVISION 0x26
|
||||
|
||||
struct ak881x {
|
||||
struct v4l2_subdev subdev;
|
||||
struct ak881x_pdata *pdata;
|
||||
unsigned int lines;
|
||||
int id; /* DEVICE_ID code V4L2_IDENT_AK881X code from v4l2-chip-ident.h */
|
||||
char revision; /* DEVICE_REVISION content */
|
||||
};
|
||||
|
||||
static int reg_read(struct i2c_client *client, const u8 reg)
|
||||
{
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int reg_write(struct i2c_client *client, const u8 reg,
|
||||
const u8 data)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(client, reg, data);
|
||||
}
|
||||
|
||||
static int reg_set(struct i2c_client *client, const u8 reg,
|
||||
const u8 data, u8 mask)
|
||||
{
|
||||
int ret = reg_read(client, reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return reg_write(client, reg, (ret & ~mask) | (data & mask));
|
||||
}
|
||||
|
||||
static struct ak881x *to_ak881x(const struct i2c_client *client)
|
||||
{
|
||||
return container_of(i2c_get_clientdata(client), struct ak881x, subdev);
|
||||
}
|
||||
|
||||
static int ak881x_g_chip_ident(struct v4l2_subdev *sd,
|
||||
struct v4l2_dbg_chip_ident *id)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct ak881x *ak881x = to_ak881x(client);
|
||||
|
||||
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
|
||||
return -EINVAL;
|
||||
|
||||
if (id->match.addr != client->addr)
|
||||
return -ENODEV;
|
||||
|
||||
id->ident = ak881x->id;
|
||||
id->revision = ak881x->revision;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
static int ak881x_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 > 0x26)
|
||||
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 ak881x_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 > 0x26)
|
||||
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 ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *mf)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct ak881x *ak881x = to_ak881x(client);
|
||||
|
||||
v4l_bound_align_image(&mf->width, 0, 720, 2,
|
||||
&mf->height, 0, ak881x->lines, 1, 0);
|
||||
mf->field = V4L2_FIELD_INTERLACED;
|
||||
mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
|
||||
mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *mf)
|
||||
{
|
||||
if (mf->field != V4L2_FIELD_INTERLACED ||
|
||||
mf->code != V4L2_MBUS_FMT_YUYV8_2X8)
|
||||
return -EINVAL;
|
||||
|
||||
return ak881x_try_g_mbus_fmt(sd, mf);
|
||||
}
|
||||
|
||||
static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
|
||||
enum v4l2_mbus_pixelcode *code)
|
||||
{
|
||||
if (index)
|
||||
return -EINVAL;
|
||||
|
||||
*code = V4L2_MBUS_FMT_YUYV8_2X8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak881x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct ak881x *ak881x = to_ak881x(client);
|
||||
|
||||
a->bounds.left = 0;
|
||||
a->bounds.top = 0;
|
||||
a->bounds.width = 720;
|
||||
a->bounds.height = ak881x->lines;
|
||||
a->defrect = a->bounds;
|
||||
a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
|
||||
a->pixelaspect.numerator = 1;
|
||||
a->pixelaspect.denominator = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak881x_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct ak881x *ak881x = to_ak881x(client);
|
||||
u8 vp1;
|
||||
|
||||
if (std == V4L2_STD_NTSC_443) {
|
||||
vp1 = 3;
|
||||
ak881x->lines = 480;
|
||||
} else if (std == V4L2_STD_PAL_M) {
|
||||
vp1 = 5;
|
||||
ak881x->lines = 480;
|
||||
} else if (std == V4L2_STD_PAL_60) {
|
||||
vp1 = 7;
|
||||
ak881x->lines = 480;
|
||||
} else if (std && !(std & ~V4L2_STD_PAL)) {
|
||||
vp1 = 0xf;
|
||||
ak881x->lines = 576;
|
||||
} else if (std && !(std & ~V4L2_STD_NTSC)) {
|
||||
vp1 = 0;
|
||||
ak881x->lines = 480;
|
||||
} else {
|
||||
/* No SECAM or PAL_N/Nc supported */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg_set(client, AK881X_VIDEO_PROCESS1, vp1, 0xf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak881x_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct ak881x *ak881x = to_ak881x(client);
|
||||
|
||||
if (enable) {
|
||||
u8 dac;
|
||||
/* For colour-bar testing set bit 6 of AK881X_VIDEO_PROCESS1 */
|
||||
/* Default: composite output */
|
||||
if (ak881x->pdata->flags & AK881X_COMPONENT)
|
||||
dac = 3;
|
||||
else
|
||||
dac = 4;
|
||||
/* Turn on the DAC(s) */
|
||||
reg_write(client, AK881X_DAC_MODE, dac);
|
||||
dev_dbg(&client->dev, "chip status 0x%x\n",
|
||||
reg_read(client, AK881X_STATUS));
|
||||
} else {
|
||||
/* ...and clear bit 6 of AK881X_VIDEO_PROCESS1 here */
|
||||
reg_write(client, AK881X_DAC_MODE, 0);
|
||||
dev_dbg(&client->dev, "chip status 0x%x\n",
|
||||
reg_read(client, AK881X_STATUS));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = {
|
||||
.g_chip_ident = ak881x_g_chip_ident,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
.g_register = ak881x_g_register,
|
||||
.s_register = ak881x_s_register,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = {
|
||||
.s_mbus_fmt = ak881x_s_mbus_fmt,
|
||||
.g_mbus_fmt = ak881x_try_g_mbus_fmt,
|
||||
.try_mbus_fmt = ak881x_try_g_mbus_fmt,
|
||||
.cropcap = ak881x_cropcap,
|
||||
.enum_mbus_fmt = ak881x_enum_mbus_fmt,
|
||||
.s_std_output = ak881x_s_std_output,
|
||||
.s_stream = ak881x_s_stream,
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_ops ak881x_subdev_ops = {
|
||||
.core = &ak881x_subdev_core_ops,
|
||||
.video = &ak881x_subdev_video_ops,
|
||||
};
|
||||
|
||||
static int ak881x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *did)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct ak881x *ak881x;
|
||||
u8 ifmode, data;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
dev_warn(&adapter->dev,
|
||||
"I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ak881x = kzalloc(sizeof(struct ak881x), GFP_KERNEL);
|
||||
if (!ak881x)
|
||||
return -ENOMEM;
|
||||
|
||||
v4l2_i2c_subdev_init(&ak881x->subdev, client, &ak881x_subdev_ops);
|
||||
|
||||
data = reg_read(client, AK881X_DEVICE_ID);
|
||||
|
||||
switch (data) {
|
||||
case 0x13:
|
||||
ak881x->id = V4L2_IDENT_AK8813;
|
||||
break;
|
||||
case 0x14:
|
||||
ak881x->id = V4L2_IDENT_AK8814;
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev,
|
||||
"No ak881x chip detected, register read %x\n", data);
|
||||
kfree(ak881x);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ak881x->revision = reg_read(client, AK881X_DEVICE_REVISION);
|
||||
ak881x->pdata = client->dev.platform_data;
|
||||
|
||||
if (ak881x->pdata) {
|
||||
if (ak881x->pdata->flags & AK881X_FIELD)
|
||||
ifmode = 4;
|
||||
else
|
||||
ifmode = 0;
|
||||
|
||||
switch (ak881x->pdata->flags & AK881X_IF_MODE_MASK) {
|
||||
case AK881X_IF_MODE_BT656:
|
||||
ifmode |= 1;
|
||||
break;
|
||||
case AK881X_IF_MODE_MASTER:
|
||||
ifmode |= 2;
|
||||
break;
|
||||
case AK881X_IF_MODE_SLAVE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev, "IF mode %x\n", ifmode);
|
||||
|
||||
/*
|
||||
* "Line Blanking No." seems to be the same as the number of
|
||||
* "black" lines on, e.g., SuperH VOU, whose default value of 20
|
||||
* "incidentally" matches ak881x' default
|
||||
*/
|
||||
reg_write(client, AK881X_INTERFACE_MODE, ifmode | (20 << 3));
|
||||
}
|
||||
|
||||
/* Hardware default: NTSC-M */
|
||||
ak881x->lines = 480;
|
||||
|
||||
dev_info(&client->dev, "Detected an ak881x chip ID %x, revision %x\n",
|
||||
data, ak881x->revision);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ak881x_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ak881x *ak881x = to_ak881x(client);
|
||||
|
||||
v4l2_device_unregister_subdev(&ak881x->subdev);
|
||||
kfree(ak881x);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ak881x_id[] = {
|
||||
{ "ak8813", 0 },
|
||||
{ "ak8814", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ak881x_id);
|
||||
|
||||
static struct i2c_driver ak881x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ak881x",
|
||||
},
|
||||
.probe = ak881x_probe,
|
||||
.remove = ak881x_remove,
|
||||
.id_table = ak881x_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(ak881x_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("TV-output driver for ak8813/ak8814");
|
||||
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
173
drivers/media/i2c/aptina-pll.c
Normal file
173
drivers/media/i2c/aptina-pll.c
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Aptina Sensor PLL Configuration
|
||||
*
|
||||
* Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/gcd.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/lcm.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "aptina-pll.h"
|
||||
|
||||
int aptina_pll_calculate(struct device *dev,
|
||||
const struct aptina_pll_limits *limits,
|
||||
struct aptina_pll *pll)
|
||||
{
|
||||
unsigned int mf_min;
|
||||
unsigned int mf_max;
|
||||
unsigned int p1_min;
|
||||
unsigned int p1_max;
|
||||
unsigned int p1;
|
||||
unsigned int div;
|
||||
|
||||
dev_dbg(dev, "PLL: ext clock %u pix clock %u\n",
|
||||
pll->ext_clock, pll->pix_clock);
|
||||
|
||||
if (pll->ext_clock < limits->ext_clock_min ||
|
||||
pll->ext_clock > limits->ext_clock_max) {
|
||||
dev_err(dev, "pll: invalid external clock frequency.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pll->pix_clock == 0 || pll->pix_clock > limits->pix_clock_max) {
|
||||
dev_err(dev, "pll: invalid pixel clock frequency.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Compute the multiplier M and combined N*P1 divisor. */
|
||||
div = gcd(pll->pix_clock, pll->ext_clock);
|
||||
pll->m = pll->pix_clock / div;
|
||||
div = pll->ext_clock / div;
|
||||
|
||||
/* We now have the smallest M and N*P1 values that will result in the
|
||||
* desired pixel clock frequency, but they might be out of the valid
|
||||
* range. Compute the factor by which we should multiply them given the
|
||||
* following constraints:
|
||||
*
|
||||
* - minimum/maximum multiplier
|
||||
* - minimum/maximum multiplier output clock frequency assuming the
|
||||
* minimum/maximum N value
|
||||
* - minimum/maximum combined N*P1 divisor
|
||||
*/
|
||||
mf_min = DIV_ROUND_UP(limits->m_min, pll->m);
|
||||
mf_min = max(mf_min, limits->out_clock_min /
|
||||
(pll->ext_clock / limits->n_min * pll->m));
|
||||
mf_min = max(mf_min, limits->n_min * limits->p1_min / div);
|
||||
mf_max = limits->m_max / pll->m;
|
||||
mf_max = min(mf_max, limits->out_clock_max /
|
||||
(pll->ext_clock / limits->n_max * pll->m));
|
||||
mf_max = min(mf_max, DIV_ROUND_UP(limits->n_max * limits->p1_max, div));
|
||||
|
||||
dev_dbg(dev, "pll: mf min %u max %u\n", mf_min, mf_max);
|
||||
if (mf_min > mf_max) {
|
||||
dev_err(dev, "pll: no valid combined N*P1 divisor.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We're looking for the highest acceptable P1 value for which a
|
||||
* multiplier factor MF exists that fulfills the following conditions:
|
||||
*
|
||||
* 1. p1 is in the [p1_min, p1_max] range given by the limits and is
|
||||
* even
|
||||
* 2. mf is in the [mf_min, mf_max] range computed above
|
||||
* 3. div * mf is a multiple of p1, in order to compute
|
||||
* n = div * mf / p1
|
||||
* m = pll->m * mf
|
||||
* 4. the internal clock frequency, given by ext_clock / n, is in the
|
||||
* [int_clock_min, int_clock_max] range given by the limits
|
||||
* 5. the output clock frequency, given by ext_clock / n * m, is in the
|
||||
* [out_clock_min, out_clock_max] range given by the limits
|
||||
*
|
||||
* The first naive approach is to iterate over all p1 values acceptable
|
||||
* according to (1) and all mf values acceptable according to (2), and
|
||||
* stop at the first combination that fulfills (3), (4) and (5). This
|
||||
* has a O(n^2) complexity.
|
||||
*
|
||||
* Instead of iterating over all mf values in the [mf_min, mf_max] range
|
||||
* we can compute the mf increment between two acceptable values
|
||||
* according to (3) with
|
||||
*
|
||||
* mf_inc = p1 / gcd(div, p1) (6)
|
||||
*
|
||||
* and round the minimum up to the nearest multiple of mf_inc. This will
|
||||
* restrict the number of mf values to be checked.
|
||||
*
|
||||
* Furthermore, conditions (4) and (5) only restrict the range of
|
||||
* acceptable p1 and mf values by modifying the minimum and maximum
|
||||
* limits. (5) can be expressed as
|
||||
*
|
||||
* ext_clock / (div * mf / p1) * m * mf >= out_clock_min
|
||||
* ext_clock / (div * mf / p1) * m * mf <= out_clock_max
|
||||
*
|
||||
* or
|
||||
*
|
||||
* p1 >= out_clock_min * div / (ext_clock * m) (7)
|
||||
* p1 <= out_clock_max * div / (ext_clock * m)
|
||||
*
|
||||
* Similarly, (4) can be expressed as
|
||||
*
|
||||
* mf >= ext_clock * p1 / (int_clock_max * div) (8)
|
||||
* mf <= ext_clock * p1 / (int_clock_min * div)
|
||||
*
|
||||
* We can thus iterate over the restricted p1 range defined by the
|
||||
* combination of (1) and (7), and then compute the restricted mf range
|
||||
* defined by the combination of (2), (6) and (8). If the resulting mf
|
||||
* range is not empty, any value in the mf range is acceptable. We thus
|
||||
* select the mf lwoer bound and the corresponding p1 value.
|
||||
*/
|
||||
if (limits->p1_min == 0) {
|
||||
dev_err(dev, "pll: P1 minimum value must be >0.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
p1_min = max(limits->p1_min, DIV_ROUND_UP(limits->out_clock_min * div,
|
||||
pll->ext_clock * pll->m));
|
||||
p1_max = min(limits->p1_max, limits->out_clock_max * div /
|
||||
(pll->ext_clock * pll->m));
|
||||
|
||||
for (p1 = p1_max & ~1; p1 >= p1_min; p1 -= 2) {
|
||||
unsigned int mf_inc = p1 / gcd(div, p1);
|
||||
unsigned int mf_high;
|
||||
unsigned int mf_low;
|
||||
|
||||
mf_low = roundup(max(mf_min, DIV_ROUND_UP(pll->ext_clock * p1,
|
||||
limits->int_clock_max * div)), mf_inc);
|
||||
mf_high = min(mf_max, pll->ext_clock * p1 /
|
||||
(limits->int_clock_min * div));
|
||||
|
||||
if (mf_low > mf_high)
|
||||
continue;
|
||||
|
||||
pll->n = div * mf_low / p1;
|
||||
pll->m *= mf_low;
|
||||
pll->p1 = p1;
|
||||
dev_dbg(dev, "PLL: N %u M %u P1 %u\n", pll->n, pll->m, pll->p1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(dev, "pll: no valid N and P1 divisors found.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(aptina_pll_calculate);
|
||||
|
||||
MODULE_DESCRIPTION("Aptina PLL Helpers");
|
||||
MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
56
drivers/media/i2c/aptina-pll.h
Normal file
56
drivers/media/i2c/aptina-pll.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Aptina Sensor PLL Configuration
|
||||
*
|
||||
* Copyright (C) 2012 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __APTINA_PLL_H
|
||||
#define __APTINA_PLL_H
|
||||
|
||||
struct aptina_pll {
|
||||
unsigned int ext_clock;
|
||||
unsigned int pix_clock;
|
||||
|
||||
unsigned int n;
|
||||
unsigned int m;
|
||||
unsigned int p1;
|
||||
};
|
||||
|
||||
struct aptina_pll_limits {
|
||||
unsigned int ext_clock_min;
|
||||
unsigned int ext_clock_max;
|
||||
unsigned int int_clock_min;
|
||||
unsigned int int_clock_max;
|
||||
unsigned int out_clock_min;
|
||||
unsigned int out_clock_max;
|
||||
unsigned int pix_clock_max;
|
||||
|
||||
unsigned int n_min;
|
||||
unsigned int n_max;
|
||||
unsigned int m_min;
|
||||
unsigned int m_max;
|
||||
unsigned int p1_min;
|
||||
unsigned int p1_max;
|
||||
};
|
||||
|
||||
struct device;
|
||||
|
||||
int aptina_pll_calculate(struct device *dev,
|
||||
const struct aptina_pll_limits *limits,
|
||||
struct aptina_pll *pll);
|
||||
|
||||
#endif /* __APTINA_PLL_H */
|
||||
888
drivers/media/i2c/as3645a.c
Normal file
888
drivers/media/i2c/as3645a.c
Normal file
|
|
@ -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");
|
||||
517
drivers/media/i2c/bt819.c
Normal file
517
drivers/media/i2c/bt819.c
Normal file
|
|
@ -0,0 +1,517 @@
|
|||
/*
|
||||
* bt819 - BT819A VideoStream Decoder (Rockwell Part)
|
||||
*
|
||||
* Copyright (C) 1999 Mike Bernson <mike@mlb.org>
|
||||
* Copyright (C) 1998 Dave Perks <dperks@ibm.net>
|
||||
*
|
||||
* Modifications for LML33/DC10plus unified driver
|
||||
* Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
|
||||
*
|
||||
* Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
* - moved over to linux>=2.4.x i2c protocol (9/9/2002)
|
||||
*
|
||||
* This code was modify/ported from the saa7111 driver written
|
||||
* by Dave Perks.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the 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/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/slab.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/bt819.h>
|
||||
|
||||
MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
|
||||
MODULE_AUTHOR("Mike Bernson & Dave Perks");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
struct bt819 {
|
||||
struct v4l2_subdev sd;
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
unsigned char reg[32];
|
||||
|
||||
v4l2_std_id norm;
|
||||
int ident;
|
||||
int input;
|
||||
int enable;
|
||||
};
|
||||
|
||||
static inline struct bt819 *to_bt819(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct bt819, sd);
|
||||
}
|
||||
|
||||
static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
return &container_of(ctrl->handler, struct bt819, hdl)->sd;
|
||||
}
|
||||
|
||||
struct timing {
|
||||
int hactive;
|
||||
int hdelay;
|
||||
int vactive;
|
||||
int vdelay;
|
||||
int hscale;
|
||||
int vscale;
|
||||
};
|
||||
|
||||
/* for values, see the bt819 datasheet */
|
||||
static struct timing timing_data[] = {
|
||||
{864 - 24, 20, 625 - 2, 1, 0x0504, 0x0000},
|
||||
{858 - 24, 20, 525 - 2, 1, 0x00f8, 0x0000},
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int bt819_write(struct bt819 *decoder, u8 reg, u8 value)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
|
||||
|
||||
decoder->reg[reg] = value;
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline int bt819_setbit(struct bt819 *decoder, u8 reg, u8 bit, u8 value)
|
||||
{
|
||||
return bt819_write(decoder, reg,
|
||||
(decoder->reg[reg] & ~(1 << bit)) | (value ? (1 << bit) : 0));
|
||||
}
|
||||
|
||||
static int bt819_write_block(struct bt819 *decoder, const u8 *data, unsigned int len)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
|
||||
int ret = -1;
|
||||
u8 reg;
|
||||
|
||||
/* the bt819 has an autoincrement function, use it if
|
||||
* the adapter understands raw I2C */
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
/* do raw I2C, not smbus compatible */
|
||||
u8 block_data[32];
|
||||
int block_len;
|
||||
|
||||
while (len >= 2) {
|
||||
block_len = 0;
|
||||
block_data[block_len++] = reg = data[0];
|
||||
do {
|
||||
block_data[block_len++] =
|
||||
decoder->reg[reg++] = data[1];
|
||||
len -= 2;
|
||||
data += 2;
|
||||
} while (len >= 2 && data[0] == reg && block_len < 32);
|
||||
ret = i2c_master_send(client, block_data, block_len);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* do some slow I2C emulation kind of thing */
|
||||
while (len >= 2) {
|
||||
reg = *data++;
|
||||
ret = bt819_write(decoder, reg, *data++);
|
||||
if (ret < 0)
|
||||
break;
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int bt819_read(struct bt819 *decoder, u8 reg)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&decoder->sd);
|
||||
|
||||
return i2c_smbus_read_byte_data(client, reg);
|
||||
}
|
||||
|
||||
static int bt819_init(struct v4l2_subdev *sd)
|
||||
{
|
||||
static unsigned char init[] = {
|
||||
/*0x1f, 0x00,*/ /* Reset */
|
||||
0x01, 0x59, /* 0x01 input format */
|
||||
0x02, 0x00, /* 0x02 temporal decimation */
|
||||
0x03, 0x12, /* 0x03 Cropping msb */
|
||||
0x04, 0x16, /* 0x04 Vertical Delay, lsb */
|
||||
0x05, 0xe0, /* 0x05 Vertical Active lsb */
|
||||
0x06, 0x80, /* 0x06 Horizontal Delay lsb */
|
||||
0x07, 0xd0, /* 0x07 Horizontal Active lsb */
|
||||
0x08, 0x00, /* 0x08 Horizontal Scaling msb */
|
||||
0x09, 0xf8, /* 0x09 Horizontal Scaling lsb */
|
||||
0x0a, 0x00, /* 0x0a Brightness control */
|
||||
0x0b, 0x30, /* 0x0b Miscellaneous control */
|
||||
0x0c, 0xd8, /* 0x0c Luma Gain lsb */
|
||||
0x0d, 0xfe, /* 0x0d Chroma Gain (U) lsb */
|
||||
0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */
|
||||
0x0f, 0x00, /* 0x0f Hue control */
|
||||
0x12, 0x04, /* 0x12 Output Format */
|
||||
0x13, 0x20, /* 0x13 Vertial Scaling msb 0x00
|
||||
chroma comb OFF, line drop scaling, interlace scaling
|
||||
BUG? Why does turning the chroma comb on fuck up color?
|
||||
Bug in the bt819 stepping on my board?
|
||||
*/
|
||||
0x14, 0x00, /* 0x14 Vertial Scaling lsb */
|
||||
0x16, 0x07, /* 0x16 Video Timing Polarity
|
||||
ACTIVE=active low
|
||||
FIELD: high=odd,
|
||||
vreset=active high,
|
||||
hreset=active high */
|
||||
0x18, 0x68, /* 0x18 AGC Delay */
|
||||
0x19, 0x5d, /* 0x19 Burst Gate Delay */
|
||||
0x1a, 0x80, /* 0x1a ADC Interface */
|
||||
};
|
||||
|
||||
struct bt819 *decoder = to_bt819(sd);
|
||||
struct timing *timing = &timing_data[(decoder->norm & V4L2_STD_525_60) ? 1 : 0];
|
||||
|
||||
init[0x03 * 2 - 1] =
|
||||
(((timing->vdelay >> 8) & 0x03) << 6) |
|
||||
(((timing->vactive >> 8) & 0x03) << 4) |
|
||||
(((timing->hdelay >> 8) & 0x03) << 2) |
|
||||
((timing->hactive >> 8) & 0x03);
|
||||
init[0x04 * 2 - 1] = timing->vdelay & 0xff;
|
||||
init[0x05 * 2 - 1] = timing->vactive & 0xff;
|
||||
init[0x06 * 2 - 1] = timing->hdelay & 0xff;
|
||||
init[0x07 * 2 - 1] = timing->hactive & 0xff;
|
||||
init[0x08 * 2 - 1] = timing->hscale >> 8;
|
||||
init[0x09 * 2 - 1] = timing->hscale & 0xff;
|
||||
/* 0x15 in array is address 0x19 */
|
||||
init[0x15 * 2 - 1] = (decoder->norm & V4L2_STD_625_50) ? 115 : 93; /* Chroma burst delay */
|
||||
/* reset */
|
||||
bt819_write(decoder, 0x1f, 0x00);
|
||||
mdelay(1);
|
||||
|
||||
/* init */
|
||||
return bt819_write_block(decoder, init, sizeof(init));
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int bt819_status(struct v4l2_subdev *sd, u32 *pstatus, v4l2_std_id *pstd)
|
||||
{
|
||||
struct bt819 *decoder = to_bt819(sd);
|
||||
int status = bt819_read(decoder, 0x00);
|
||||
int res = V4L2_IN_ST_NO_SIGNAL;
|
||||
v4l2_std_id std;
|
||||
|
||||
if ((status & 0x80))
|
||||
res = 0;
|
||||
|
||||
if ((status & 0x10))
|
||||
std = V4L2_STD_PAL;
|
||||
else
|
||||
std = V4L2_STD_NTSC;
|
||||
if (pstd)
|
||||
*pstd = std;
|
||||
if (pstatus)
|
||||
*pstatus = res;
|
||||
|
||||
v4l2_dbg(1, debug, sd, "get status %x\n", status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt819_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
|
||||
{
|
||||
return bt819_status(sd, NULL, std);
|
||||
}
|
||||
|
||||
static int bt819_g_input_status(struct v4l2_subdev *sd, u32 *status)
|
||||
{
|
||||
return bt819_status(sd, status, NULL);
|
||||
}
|
||||
|
||||
static int bt819_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct bt819 *decoder = to_bt819(sd);
|
||||
struct timing *timing = NULL;
|
||||
|
||||
v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
|
||||
|
||||
if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
|
||||
v4l2_err(sd, "no notify found!\n");
|
||||
|
||||
if (std & V4L2_STD_NTSC) {
|
||||
v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
|
||||
bt819_setbit(decoder, 0x01, 0, 1);
|
||||
bt819_setbit(decoder, 0x01, 1, 0);
|
||||
bt819_setbit(decoder, 0x01, 5, 0);
|
||||
bt819_write(decoder, 0x18, 0x68);
|
||||
bt819_write(decoder, 0x19, 0x5d);
|
||||
/* bt819_setbit(decoder, 0x1a, 5, 1); */
|
||||
timing = &timing_data[1];
|
||||
} else if (std & V4L2_STD_PAL) {
|
||||
v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
|
||||
bt819_setbit(decoder, 0x01, 0, 1);
|
||||
bt819_setbit(decoder, 0x01, 1, 1);
|
||||
bt819_setbit(decoder, 0x01, 5, 1);
|
||||
bt819_write(decoder, 0x18, 0x7f);
|
||||
bt819_write(decoder, 0x19, 0x72);
|
||||
/* bt819_setbit(decoder, 0x1a, 5, 0); */
|
||||
timing = &timing_data[0];
|
||||
} else {
|
||||
v4l2_dbg(1, debug, sd, "unsupported norm %llx\n",
|
||||
(unsigned long long)std);
|
||||
return -EINVAL;
|
||||
}
|
||||
bt819_write(decoder, 0x03,
|
||||
(((timing->vdelay >> 8) & 0x03) << 6) |
|
||||
(((timing->vactive >> 8) & 0x03) << 4) |
|
||||
(((timing->hdelay >> 8) & 0x03) << 2) |
|
||||
((timing->hactive >> 8) & 0x03));
|
||||
bt819_write(decoder, 0x04, timing->vdelay & 0xff);
|
||||
bt819_write(decoder, 0x05, timing->vactive & 0xff);
|
||||
bt819_write(decoder, 0x06, timing->hdelay & 0xff);
|
||||
bt819_write(decoder, 0x07, timing->hactive & 0xff);
|
||||
bt819_write(decoder, 0x08, (timing->hscale >> 8) & 0xff);
|
||||
bt819_write(decoder, 0x09, timing->hscale & 0xff);
|
||||
decoder->norm = std;
|
||||
v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt819_s_routing(struct v4l2_subdev *sd,
|
||||
u32 input, u32 output, u32 config)
|
||||
{
|
||||
struct bt819 *decoder = to_bt819(sd);
|
||||
|
||||
v4l2_dbg(1, debug, sd, "set input %x\n", input);
|
||||
|
||||
if (input > 7)
|
||||
return -EINVAL;
|
||||
|
||||
if (sd->v4l2_dev == NULL || sd->v4l2_dev->notify == NULL)
|
||||
v4l2_err(sd, "no notify found!\n");
|
||||
|
||||
if (decoder->input != input) {
|
||||
v4l2_subdev_notify(sd, BT819_FIFO_RESET_LOW, NULL);
|
||||
decoder->input = input;
|
||||
/* select mode */
|
||||
if (decoder->input == 0) {
|
||||
bt819_setbit(decoder, 0x0b, 6, 0);
|
||||
bt819_setbit(decoder, 0x1a, 1, 1);
|
||||
} else {
|
||||
bt819_setbit(decoder, 0x0b, 6, 1);
|
||||
bt819_setbit(decoder, 0x1a, 1, 0);
|
||||
}
|
||||
v4l2_subdev_notify(sd, BT819_FIFO_RESET_HIGH, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt819_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
{
|
||||
struct bt819 *decoder = to_bt819(sd);
|
||||
|
||||
v4l2_dbg(1, debug, sd, "enable output %x\n", enable);
|
||||
|
||||
if (decoder->enable != enable) {
|
||||
decoder->enable = enable;
|
||||
bt819_setbit(decoder, 0x16, 7, !enable);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt819_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct v4l2_subdev *sd = to_sd(ctrl);
|
||||
struct bt819 *decoder = to_bt819(sd);
|
||||
int temp;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_BRIGHTNESS:
|
||||
bt819_write(decoder, 0x0a, ctrl->val);
|
||||
break;
|
||||
|
||||
case V4L2_CID_CONTRAST:
|
||||
bt819_write(decoder, 0x0c, ctrl->val & 0xff);
|
||||
bt819_setbit(decoder, 0x0b, 2, ((ctrl->val >> 8) & 0x01));
|
||||
break;
|
||||
|
||||
case V4L2_CID_SATURATION:
|
||||
bt819_write(decoder, 0x0d, (ctrl->val >> 7) & 0xff);
|
||||
bt819_setbit(decoder, 0x0b, 1, ((ctrl->val >> 15) & 0x01));
|
||||
|
||||
/* Ratio between U gain and V gain must stay the same as
|
||||
the ratio between the default U and V gain values. */
|
||||
temp = (ctrl->val * 180) / 254;
|
||||
bt819_write(decoder, 0x0e, (temp >> 7) & 0xff);
|
||||
bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01);
|
||||
break;
|
||||
|
||||
case V4L2_CID_HUE:
|
||||
bt819_write(decoder, 0x0f, ctrl->val);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
struct bt819 *decoder = to_bt819(sd);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, decoder->ident, 0);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct v4l2_ctrl_ops bt819_ctrl_ops = {
|
||||
.s_ctrl = bt819_s_ctrl,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops bt819_core_ops = {
|
||||
.g_chip_ident = bt819_g_chip_ident,
|
||||
.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 = bt819_s_std,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops bt819_video_ops = {
|
||||
.s_routing = bt819_s_routing,
|
||||
.s_stream = bt819_s_stream,
|
||||
.querystd = bt819_querystd,
|
||||
.g_input_status = bt819_g_input_status,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops bt819_ops = {
|
||||
.core = &bt819_core_ops,
|
||||
.video = &bt819_video_ops,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int bt819_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int i, ver;
|
||||
struct bt819 *decoder;
|
||||
struct v4l2_subdev *sd;
|
||||
const char *name;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
decoder = kzalloc(sizeof(struct bt819), GFP_KERNEL);
|
||||
if (decoder == NULL)
|
||||
return -ENOMEM;
|
||||
sd = &decoder->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &bt819_ops);
|
||||
|
||||
ver = bt819_read(decoder, 0x17);
|
||||
switch (ver & 0xf0) {
|
||||
case 0x70:
|
||||
name = "bt819a";
|
||||
decoder->ident = V4L2_IDENT_BT819A;
|
||||
break;
|
||||
case 0x60:
|
||||
name = "bt817a";
|
||||
decoder->ident = V4L2_IDENT_BT817A;
|
||||
break;
|
||||
case 0x20:
|
||||
name = "bt815a";
|
||||
decoder->ident = V4L2_IDENT_BT815A;
|
||||
break;
|
||||
default:
|
||||
v4l2_dbg(1, debug, sd,
|
||||
"unknown chip version 0x%02x\n", ver);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
v4l_info(client, "%s found @ 0x%x (%s)\n", name,
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
decoder->norm = V4L2_STD_NTSC;
|
||||
decoder->input = 0;
|
||||
decoder->enable = 1;
|
||||
|
||||
i = bt819_init(sd);
|
||||
if (i < 0)
|
||||
v4l2_dbg(1, debug, sd, "init status %d\n", i);
|
||||
|
||||
v4l2_ctrl_handler_init(&decoder->hdl, 4);
|
||||
v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
|
||||
V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
|
||||
v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
|
||||
V4L2_CID_CONTRAST, 0, 511, 1, 0xd8);
|
||||
v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
|
||||
V4L2_CID_SATURATION, 0, 511, 1, 0xfe);
|
||||
v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
|
||||
V4L2_CID_HUE, -128, 127, 1, 0);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt819_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
struct bt819 *decoder = to_bt819(sd);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(&decoder->hdl);
|
||||
kfree(decoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct i2c_device_id bt819_id[] = {
|
||||
{ "bt819a", 0 },
|
||||
{ "bt817a", 0 },
|
||||
{ "bt815a", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bt819_id);
|
||||
|
||||
static struct i2c_driver bt819_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "bt819",
|
||||
},
|
||||
.probe = bt819_probe,
|
||||
.remove = bt819_remove,
|
||||
.id_table = bt819_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(bt819_driver);
|
||||
273
drivers/media/i2c/bt856.c
Normal file
273
drivers/media/i2c/bt856.c
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* bt856 - BT856A Digital Video Encoder (Rockwell Part)
|
||||
*
|
||||
* Copyright (C) 1999 Mike Bernson <mike@mlb.org>
|
||||
* Copyright (C) 1998 Dave Perks <dperks@ibm.net>
|
||||
*
|
||||
* Modifications for LML33/DC10plus unified driver
|
||||
* Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
|
||||
*
|
||||
* This code was modify/ported from the saa7111 driver written
|
||||
* by Dave Perks.
|
||||
*
|
||||
* Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
|
||||
* - moved over to linux>=2.4.x i2c protocol (9/9/2002)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the 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/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-chip-ident.h>
|
||||
|
||||
MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
|
||||
MODULE_AUTHOR("Mike Bernson & Dave Perks");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0);
|
||||
MODULE_PARM_DESC(debug, "Debug level (0-1)");
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
#define BT856_REG_OFFSET 0xDA
|
||||
#define BT856_NR_REG 6
|
||||
|
||||
struct bt856 {
|
||||
struct v4l2_subdev sd;
|
||||
unsigned char reg[BT856_NR_REG];
|
||||
|
||||
v4l2_std_id norm;
|
||||
};
|
||||
|
||||
static inline struct bt856 *to_bt856(struct v4l2_subdev *sd)
|
||||
{
|
||||
return container_of(sd, struct bt856, sd);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static inline int bt856_write(struct bt856 *encoder, u8 reg, u8 value)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
|
||||
|
||||
encoder->reg[reg - BT856_REG_OFFSET] = value;
|
||||
return i2c_smbus_write_byte_data(client, reg, value);
|
||||
}
|
||||
|
||||
static inline int bt856_setbit(struct bt856 *encoder, u8 reg, u8 bit, u8 value)
|
||||
{
|
||||
return bt856_write(encoder, reg,
|
||||
(encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
|
||||
(value ? (1 << bit) : 0));
|
||||
}
|
||||
|
||||
static void bt856_dump(struct bt856 *encoder)
|
||||
{
|
||||
int i;
|
||||
|
||||
v4l2_info(&encoder->sd, "register dump:\n");
|
||||
for (i = 0; i < BT856_NR_REG; i += 2)
|
||||
printk(KERN_CONT " %02x", encoder->reg[i]);
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int bt856_init(struct v4l2_subdev *sd, u32 arg)
|
||||
{
|
||||
struct bt856 *encoder = to_bt856(sd);
|
||||
|
||||
/* This is just for testing!!! */
|
||||
v4l2_dbg(1, debug, sd, "init\n");
|
||||
bt856_write(encoder, 0xdc, 0x18);
|
||||
bt856_write(encoder, 0xda, 0);
|
||||
bt856_write(encoder, 0xde, 0);
|
||||
|
||||
bt856_setbit(encoder, 0xdc, 3, 1);
|
||||
/*bt856_setbit(encoder, 0xdc, 6, 0);*/
|
||||
bt856_setbit(encoder, 0xdc, 4, 1);
|
||||
|
||||
if (encoder->norm & V4L2_STD_NTSC)
|
||||
bt856_setbit(encoder, 0xdc, 2, 0);
|
||||
else
|
||||
bt856_setbit(encoder, 0xdc, 2, 1);
|
||||
|
||||
bt856_setbit(encoder, 0xdc, 1, 1);
|
||||
bt856_setbit(encoder, 0xde, 4, 0);
|
||||
bt856_setbit(encoder, 0xde, 3, 1);
|
||||
if (debug != 0)
|
||||
bt856_dump(encoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt856_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
|
||||
{
|
||||
struct bt856 *encoder = to_bt856(sd);
|
||||
|
||||
v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
|
||||
|
||||
if (std & V4L2_STD_NTSC) {
|
||||
bt856_setbit(encoder, 0xdc, 2, 0);
|
||||
} else if (std & V4L2_STD_PAL) {
|
||||
bt856_setbit(encoder, 0xdc, 2, 1);
|
||||
bt856_setbit(encoder, 0xda, 0, 0);
|
||||
/*bt856_setbit(encoder, 0xda, 0, 1);*/
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
encoder->norm = std;
|
||||
if (debug != 0)
|
||||
bt856_dump(encoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt856_s_routing(struct v4l2_subdev *sd,
|
||||
u32 input, u32 output, u32 config)
|
||||
{
|
||||
struct bt856 *encoder = to_bt856(sd);
|
||||
|
||||
v4l2_dbg(1, debug, sd, "set input %d\n", input);
|
||||
|
||||
/* We only have video bus.
|
||||
* input= 0: input is from bt819
|
||||
* input= 1: input is from ZR36060 */
|
||||
switch (input) {
|
||||
case 0:
|
||||
bt856_setbit(encoder, 0xde, 4, 0);
|
||||
bt856_setbit(encoder, 0xde, 3, 1);
|
||||
bt856_setbit(encoder, 0xdc, 3, 1);
|
||||
bt856_setbit(encoder, 0xdc, 6, 0);
|
||||
break;
|
||||
case 1:
|
||||
bt856_setbit(encoder, 0xde, 4, 0);
|
||||
bt856_setbit(encoder, 0xde, 3, 1);
|
||||
bt856_setbit(encoder, 0xdc, 3, 1);
|
||||
bt856_setbit(encoder, 0xdc, 6, 1);
|
||||
break;
|
||||
case 2: /* Color bar */
|
||||
bt856_setbit(encoder, 0xdc, 3, 0);
|
||||
bt856_setbit(encoder, 0xde, 4, 1);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (debug != 0)
|
||||
bt856_dump(encoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt856_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT856, 0);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct v4l2_subdev_core_ops bt856_core_ops = {
|
||||
.g_chip_ident = bt856_g_chip_ident,
|
||||
.init = bt856_init,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops bt856_video_ops = {
|
||||
.s_std_output = bt856_s_std_output,
|
||||
.s_routing = bt856_s_routing,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops bt856_ops = {
|
||||
.core = &bt856_core_ops,
|
||||
.video = &bt856_video_ops,
|
||||
};
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static int bt856_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct bt856 *encoder;
|
||||
struct v4l2_subdev *sd;
|
||||
|
||||
/* Check if the adapter supports the needed features */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
v4l_info(client, "chip found @ 0x%x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL);
|
||||
if (encoder == NULL)
|
||||
return -ENOMEM;
|
||||
sd = &encoder->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &bt856_ops);
|
||||
encoder->norm = V4L2_STD_NTSC;
|
||||
|
||||
bt856_write(encoder, 0xdc, 0x18);
|
||||
bt856_write(encoder, 0xda, 0);
|
||||
bt856_write(encoder, 0xde, 0);
|
||||
|
||||
bt856_setbit(encoder, 0xdc, 3, 1);
|
||||
/*bt856_setbit(encoder, 0xdc, 6, 0);*/
|
||||
bt856_setbit(encoder, 0xdc, 4, 1);
|
||||
|
||||
if (encoder->norm & V4L2_STD_NTSC)
|
||||
bt856_setbit(encoder, 0xdc, 2, 0);
|
||||
else
|
||||
bt856_setbit(encoder, 0xdc, 2, 1);
|
||||
|
||||
bt856_setbit(encoder, 0xdc, 1, 1);
|
||||
bt856_setbit(encoder, 0xde, 4, 0);
|
||||
bt856_setbit(encoder, 0xde, 3, 1);
|
||||
|
||||
if (debug != 0)
|
||||
bt856_dump(encoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bt856_remove(struct i2c_client *client)
|
||||
{
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
kfree(to_bt856(sd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id bt856_id[] = {
|
||||
{ "bt856", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bt856_id);
|
||||
|
||||
static struct i2c_driver bt856_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "bt856",
|
||||
},
|
||||
.probe = bt856_probe,
|
||||
.remove = bt856_remove,
|
||||
.id_table = bt856_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(bt856_driver);
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue