16789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors/*
26789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * adv7180.c Analog Devices ADV7180 video decoder driver
36789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * Copyright (c) 2009 Intel Corporation
4cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov * Copyright (C) 2013 Cogent Embedded, Inc.
5cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov * Copyright (C) 2013 Renesas Solutions Corp.
66789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors *
76789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * This program is free software; you can redistribute it and/or modify
86789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * it under the terms of the GNU General Public License version 2 as
96789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * published by the Free Software Foundation.
106789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors *
116789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * This program is distributed in the hope that it will be useful,
126789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * but WITHOUT ANY WARRANTY; without even the implied warranty of
136789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
146789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * GNU General Public License for more details.
156789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors *
166789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * You should have received a copy of the GNU General Public License
176789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * along with this program; if not, write to the Free Software
186789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
196789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors */
206789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
216789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#include <linux/module.h>
226789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#include <linux/init.h>
236789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#include <linux/errno.h>
246789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#include <linux/kernel.h>
256789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#include <linux/interrupt.h>
266789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#include <linux/i2c.h>
275a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
286789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#include <media/v4l2-ioctl.h>
296789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#include <linux/videodev2.h>
306789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#include <media/v4l2-device.h>
31c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#include <media/v4l2-ctrls.h>
3242752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#include <linux/mutex.h>
336789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
34d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_REG			0x00
35d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM	0x00
36d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
37d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM	0x20
38d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM	0x30
39d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_NTSC_J			0x40
40d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_NTSC_M			0x50
41d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_PAL60			0x60
42d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_NTSC_443			0x70
43d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_PAL_BG			0x80
44d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_PAL_N			0x90
45d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_PAL_M			0xa0
46d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_PAL_M_PED			0xb0
47d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_PAL_COMB_N		0xc0
48d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED		0xd0
49d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_PAL_SECAM			0xe0
50d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED		0xf0
51bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_INPUT_CONTROL_INSEL_MASK		0x0f
52d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors
5342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG		0x04
5442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS		0xC5
556789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
5642752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_AUTODETECT_ENABLE_REG			0x07
5742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_AUTODETECT_DEFAULT			0x7f
58c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga/* Contrast */
59bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_CON_REG		0x08	/*Unsigned */
60c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_CON_MIN		0
61c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_CON_DEF		128
62c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_CON_MAX		255
63c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga/* Brightness*/
64bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_BRI_REG		0x0a	/*Signed */
65c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_BRI_MIN		-128
66c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_BRI_DEF		0
67c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_BRI_MAX		127
68c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga/* Hue */
69bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_HUE_REG		0x0b	/*Signed, inverted */
70c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_HUE_MIN		-127
71c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_HUE_DEF		0
72c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_HUE_MAX		128
73bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
7442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_ADI_CTRL_REG				0x0e
7542752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_ADI_CTRL_IRQ_SPACE			0x20
766789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
77bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_PWR_MAN_REG		0x0f
78bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_PWR_MAN_ON		0x04
79bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_PWR_MAN_OFF		0x24
80bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_PWR_MAN_RES		0x80
81bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
82d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_STATUS1_REG				0x10
83d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_STATUS1_IN_LOCK		0x01
84d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors#define ADV7180_STATUS1_AUTOD_MASK	0x70
856789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#define ADV7180_STATUS1_AUTOD_NTSM_M_J	0x00
866789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10
876789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#define ADV7180_STATUS1_AUTOD_PAL_M	0x20
886789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#define ADV7180_STATUS1_AUTOD_PAL_60	0x30
896789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#define ADV7180_STATUS1_AUTOD_PAL_B_G	0x40
906789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#define ADV7180_STATUS1_AUTOD_SECAM	0x50
916789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#define ADV7180_STATUS1_AUTOD_PAL_COMB	0x60
926789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#define ADV7180_STATUS1_AUTOD_SECAM_525	0x70
936789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
946789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#define ADV7180_IDENT_REG 0x11
956789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors#define ADV7180_ID_7180 0x18
966789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
9742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_ICONF1_ADI		0x40
9842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_ICONF1_ACTIVE_LOW	0x01
9942752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_ICONF1_PSYNC_ONLY	0x10
10042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_ICONF1_ACTIVE_TO_CLR	0xC0
101c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga/* Saturation */
102bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_SD_SAT_CB_REG	0xe3	/*Unsigned */
103bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_SD_SAT_CR_REG	0xe4	/*Unsigned */
104c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_SAT_MIN		0
105c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_SAT_DEF		128
106c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define ADV7180_SAT_MAX		255
107bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
10842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_IRQ1_LOCK	0x01
10942752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_IRQ1_UNLOCK	0x02
11042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_ISR1_ADI	0x42
11142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_ICR1_ADI	0x43
11242752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_IMR1_ADI	0x44
11342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_IMR2_ADI	0x48
11442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_IRQ3_AD_CHANGE	0x08
11542752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_ISR3_ADI	0x4A
11642752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_ICR3_ADI	0x4B
11742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_IMR3_ADI	0x4C
11842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors#define ADV7180_IMR4_ADI	0x50
1196789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
120bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_NTSC_V_BIT_END_REG	0xE6
121bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND	0x4F
122bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
1236789cb5230f8b06271b6a89ace20449af14be303Richard Röjforsstruct adv7180_state {
124c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	struct v4l2_ctrl_handler ctrl_hdl;
125c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	struct v4l2_subdev	sd;
12642752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	struct mutex		mutex; /* mutual excl. when accessing chip */
12742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	int			irq;
128c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	v4l2_std_id		curr_norm;
129c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	bool			autodetect;
130e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	bool			powered;
131bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	u8			input;
1326789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors};
133c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler,		\
134c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga					    struct adv7180_state,	\
135c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga					    ctrl_hdl)->sd)
1366789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
137d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjforsstatic v4l2_std_id adv7180_std_to_v4l2(u8 status1)
1386789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors{
139b294a1921454fbcc6e983750ae977ce8a28f31bcVladimir Barinov	/* in case V4L2_IN_ST_NO_SIGNAL */
140b294a1921454fbcc6e983750ae977ce8a28f31bcVladimir Barinov	if (!(status1 & ADV7180_STATUS1_IN_LOCK))
141b294a1921454fbcc6e983750ae977ce8a28f31bcVladimir Barinov		return V4L2_STD_UNKNOWN;
142b294a1921454fbcc6e983750ae977ce8a28f31bcVladimir Barinov
1436789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
1446789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	case ADV7180_STATUS1_AUTOD_NTSM_M_J:
145d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors		return V4L2_STD_NTSC;
1466789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	case ADV7180_STATUS1_AUTOD_NTSC_4_43:
1476789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors		return V4L2_STD_NTSC_443;
1486789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	case ADV7180_STATUS1_AUTOD_PAL_M:
1496789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors		return V4L2_STD_PAL_M;
1506789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	case ADV7180_STATUS1_AUTOD_PAL_60:
1516789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors		return V4L2_STD_PAL_60;
1526789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	case ADV7180_STATUS1_AUTOD_PAL_B_G:
1536789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors		return V4L2_STD_PAL;
1546789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	case ADV7180_STATUS1_AUTOD_SECAM:
1556789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors		return V4L2_STD_SECAM;
1566789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	case ADV7180_STATUS1_AUTOD_PAL_COMB:
1576789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors		return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
1586789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	case ADV7180_STATUS1_AUTOD_SECAM_525:
1596789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors		return V4L2_STD_SECAM;
1606789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	default:
1616789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors		return V4L2_STD_UNKNOWN;
1626789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	}
1636789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors}
1646789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
165c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjforsstatic int v4l2_std_to_adv7180(v4l2_std_id std)
166c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors{
167c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	if (std == V4L2_STD_PAL_60)
168c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		return ADV7180_INPUT_CONTROL_PAL60;
169c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	if (std == V4L2_STD_NTSC_443)
170c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		return ADV7180_INPUT_CONTROL_NTSC_443;
171c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	if (std == V4L2_STD_PAL_N)
172c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		return ADV7180_INPUT_CONTROL_PAL_N;
173c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	if (std == V4L2_STD_PAL_M)
174c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		return ADV7180_INPUT_CONTROL_PAL_M;
175c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	if (std == V4L2_STD_PAL_Nc)
176c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		return ADV7180_INPUT_CONTROL_PAL_COMB_N;
177c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors
178c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	if (std & V4L2_STD_PAL)
179c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		return ADV7180_INPUT_CONTROL_PAL_BG;
180c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	if (std & V4L2_STD_NTSC)
181c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		return ADV7180_INPUT_CONTROL_NTSC_M;
182c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	if (std & V4L2_STD_SECAM)
183c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		return ADV7180_INPUT_CONTROL_PAL_SECAM;
184c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors
185c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	return -EINVAL;
186c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors}
187c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors
188d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjforsstatic u32 adv7180_status_to_v4l2(u8 status1)
189d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors{
190d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors	if (!(status1 & ADV7180_STATUS1_IN_LOCK))
191d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors		return V4L2_IN_ST_NO_SIGNAL;
192d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors
193d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors	return 0;
194d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors}
195d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors
196d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjforsstatic int __adv7180_status(struct i2c_client *client, u32 *status,
197bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga			    v4l2_std_id *std)
198d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors{
199d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors	int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
200d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors
201d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors	if (status1 < 0)
202d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors		return status1;
203d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors
204d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors	if (status)
205d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors		*status = adv7180_status_to_v4l2(status1);
206d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors	if (std)
207d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors		*std = adv7180_std_to_v4l2(status1);
208d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors
209d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors	return 0;
210d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors}
211d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors
2126789cb5230f8b06271b6a89ace20449af14be303Richard Röjforsstatic inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
2136789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors{
2146789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	return container_of(sd, struct adv7180_state, sd);
2156789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors}
2166789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
2176789cb5230f8b06271b6a89ace20449af14be303Richard Röjforsstatic int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
2186789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors{
219c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	struct adv7180_state *state = to_state(sd);
22042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	int err = mutex_lock_interruptible(&state->mutex);
22142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	if (err)
22242752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		return err;
223c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors
22442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	/* when we are interrupt driven we know the state */
22542752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	if (!state->autodetect || state->irq > 0)
226c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		*std = state->curr_norm;
227c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	else
228c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
229c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors
23042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	mutex_unlock(&state->mutex);
231c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	return err;
232d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors}
2336789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
234bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vagastatic int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
235bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga			     u32 output, u32 config)
236bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga{
237bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	struct adv7180_state *state = to_state(sd);
238bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	int ret = mutex_lock_interruptible(&state->mutex);
239bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	struct i2c_client *client = v4l2_get_subdevdata(sd);
240bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
241bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	if (ret)
242bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		return ret;
243bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
244c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	/* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
245bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	 * all inputs and let the card driver take care of validation
246bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	 */
247bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
248bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		goto out;
249bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
250bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG);
251bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
252bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	if (ret < 0)
253bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		goto out;
254bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
255bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
256bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	ret = i2c_smbus_write_byte_data(client,
257bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga					ADV7180_INPUT_CONTROL_REG, ret | input);
258bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	state->input = input;
259bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vagaout:
260bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	mutex_unlock(&state->mutex);
261bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	return ret;
262bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga}
263bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
264d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjforsstatic int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
265d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors{
26642752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	struct adv7180_state *state = to_state(sd);
26742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	int ret = mutex_lock_interruptible(&state->mutex);
26842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	if (ret)
26942752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		return ret;
27042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
27142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
27242752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	mutex_unlock(&state->mutex);
27342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	return ret;
2746789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors}
2756789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
276c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjforsstatic int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
277c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors{
278c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	struct adv7180_state *state = to_state(sd);
279c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	struct i2c_client *client = v4l2_get_subdevdata(sd);
28042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	int ret = mutex_lock_interruptible(&state->mutex);
28142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	if (ret)
28242752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		return ret;
283c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors
284c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	/* all standards -> autodetect */
285c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	if (std == V4L2_STD_ALL) {
286bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		ret =
287bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
288bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
289bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga					      | state->input);
290c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		if (ret < 0)
291c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors			goto out;
292c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors
29342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		__adv7180_status(client, NULL, &state->curr_norm);
294c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		state->autodetect = true;
295c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	} else {
296c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		ret = v4l2_std_to_adv7180(std);
297c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		if (ret < 0)
298c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors			goto out;
299c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors
300c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		ret = i2c_smbus_write_byte_data(client,
301bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga						ADV7180_INPUT_CONTROL_REG,
302bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga						ret | state->input);
303c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		if (ret < 0)
304c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors			goto out;
305c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors
306c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		state->curr_norm = std;
307c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors		state->autodetect = false;
308c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	}
309c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	ret = 0;
310c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjforsout:
31142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	mutex_unlock(&state->mutex);
312c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors	return ret;
313c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors}
314c277b60a08fe9e201656528b3f5cd35b554e24afRichard Röjfors
315e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausenstatic int adv7180_set_power(struct adv7180_state *state,
316e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	struct i2c_client *client, bool on)
317e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen{
318e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	u8 val;
319e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen
320e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	if (on)
321e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen		val = ADV7180_PWR_MAN_ON;
322e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	else
323e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen		val = ADV7180_PWR_MAN_OFF;
324e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen
325e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	return i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, val);
326e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen}
327e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen
328e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausenstatic int adv7180_s_power(struct v4l2_subdev *sd, int on)
329e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen{
330e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	struct adv7180_state *state = to_state(sd);
331e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	struct i2c_client *client = v4l2_get_subdevdata(sd);
332e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	int ret;
333e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen
334e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	ret = mutex_lock_interruptible(&state->mutex);
335e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	if (ret)
336e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen		return ret;
337e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen
338e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	ret = adv7180_set_power(state, client, on);
339e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	if (ret == 0)
340e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen		state->powered = on;
341e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen
342e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	mutex_unlock(&state->mutex);
343e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	return ret;
344e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen}
345e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen
346c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vagastatic int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
347bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga{
348c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
349bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	struct adv7180_state *state = to_state(sd);
350bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	struct i2c_client *client = v4l2_get_subdevdata(sd);
351bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	int ret = mutex_lock_interruptible(&state->mutex);
352c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	int val;
353c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga
354bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	if (ret)
355bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		return ret;
356c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	val = ctrl->val;
357bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	switch (ctrl->id) {
358bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	case V4L2_CID_BRIGHTNESS:
359c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga		ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, val);
360bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		break;
361bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	case V4L2_CID_HUE:
362bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		/*Hue is inverted according to HSL chart */
363c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga		ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, -val);
364bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		break;
365bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	case V4L2_CID_CONTRAST:
366c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga		ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, val);
367bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		break;
368bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	case V4L2_CID_SATURATION:
369bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		/*
370bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
371bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		 *Let's not confuse the user, everybody understands saturation
372bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		 */
373c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga		ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG,
374c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga						val);
375bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		if (ret < 0)
376bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga			break;
377c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga		ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG,
378c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga						val);
379bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		break;
380bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	default:
381bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		ret = -EINVAL;
382bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	}
383bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
384bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	mutex_unlock(&state->mutex);
385bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	return ret;
386bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga}
387bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
388c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vagastatic const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
389c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	.s_ctrl = adv7180_s_ctrl,
390c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga};
391c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga
392c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vagastatic int adv7180_init_controls(struct adv7180_state *state)
393c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga{
394c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
395c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga
396c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
397c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga			  V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN,
398c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga			  ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF);
399c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
400c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga			  V4L2_CID_CONTRAST, ADV7180_CON_MIN,
401c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga			  ADV7180_CON_MAX, 1, ADV7180_CON_DEF);
402c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
403c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga			  V4L2_CID_SATURATION, ADV7180_SAT_MIN,
404c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga			  ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF);
405c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
406c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga			  V4L2_CID_HUE, ADV7180_HUE_MIN,
407c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga			  ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
408c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	state->sd.ctrl_handler = &state->ctrl_hdl;
409c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	if (state->ctrl_hdl.error) {
410c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga		int err = state->ctrl_hdl.error;
411c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga
412c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga		v4l2_ctrl_handler_free(&state->ctrl_hdl);
413c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga		return err;
414c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	}
415c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	v4l2_ctrl_handler_setup(&state->ctrl_hdl);
416c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga
417c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	return 0;
418c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga}
419c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vagastatic void adv7180_exit_controls(struct adv7180_state *state)
420c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga{
421c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	v4l2_ctrl_handler_free(&state->ctrl_hdl);
422c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga}
423c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga
424cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinovstatic int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
425cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov				 enum v4l2_mbus_pixelcode *code)
426cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov{
427cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	if (index > 0)
428cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov		return -EINVAL;
429cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov
430cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	*code = V4L2_MBUS_FMT_YUYV8_2X8;
431cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov
432cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	return 0;
433cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov}
434cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov
435cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinovstatic int adv7180_mbus_fmt(struct v4l2_subdev *sd,
436cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov			    struct v4l2_mbus_framefmt *fmt)
437cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov{
438cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	struct adv7180_state *state = to_state(sd);
439cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov
440cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
441cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
442cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	fmt->field = V4L2_FIELD_INTERLACED;
443cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	fmt->width = 720;
444cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
445cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov
446cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	return 0;
447cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov}
448cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov
449cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinovstatic int adv7180_g_mbus_config(struct v4l2_subdev *sd,
450cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov				 struct v4l2_mbus_config *cfg)
451cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov{
452cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	/*
453cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	 * The ADV7180 sensor supports BT.601/656 output modes.
454cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	 * The BT.656 is default and not yet configurable by s/w.
455cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	 */
456cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
457cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov		     V4L2_MBUS_DATA_ACTIVE_HIGH;
458cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	cfg->type = V4L2_MBUS_BT656;
459cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov
460cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	return 0;
461cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov}
462cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov
4636789cb5230f8b06271b6a89ace20449af14be303Richard Röjforsstatic const struct v4l2_subdev_video_ops adv7180_video_ops = {
4648774bed9ce832d8d9ccb79e92800b808aa2d2ad2Laurent Pinchart	.s_std = adv7180_s_std,
4656789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	.querystd = adv7180_querystd,
466d31242943a73aba0e5cfd0ea674b5e694b4a39e6Richard Röjfors	.g_input_status = adv7180_g_input_status,
467bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	.s_routing = adv7180_s_routing,
468cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	.enum_mbus_fmt = adv7180_enum_mbus_fmt,
469cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	.try_mbus_fmt = adv7180_mbus_fmt,
470cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	.g_mbus_fmt = adv7180_mbus_fmt,
471cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	.s_mbus_fmt = adv7180_mbus_fmt,
472cccb83f7a1848a8b2dda6480c2dc26e80710e50bVladimir Barinov	.g_mbus_config = adv7180_g_mbus_config,
4736789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors};
4746789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
4756789cb5230f8b06271b6a89ace20449af14be303Richard Röjforsstatic const struct v4l2_subdev_core_ops adv7180_core_ops = {
476e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	.s_power = adv7180_s_power,
4776789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors};
4786789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
4796789cb5230f8b06271b6a89ace20449af14be303Richard Röjforsstatic const struct v4l2_subdev_ops adv7180_ops = {
4806789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	.core = &adv7180_core_ops,
4816789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	.video = &adv7180_video_ops,
4826789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors};
4836789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
4840c25534d456535a879aba482dc14795213312514Lars-Peter Clausenstatic irqreturn_t adv7180_irq(int irq, void *devid)
48542752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors{
4860c25534d456535a879aba482dc14795213312514Lars-Peter Clausen	struct adv7180_state *state = devid;
48742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
48842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	u8 isr3;
48942752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
49042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	mutex_lock(&state->mutex);
49142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
492bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga				  ADV7180_ADI_CTRL_IRQ_SPACE);
49342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
49442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	/* clear */
49542752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
49642752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
49742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
49842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
49942752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		__adv7180_status(client, NULL, &state->curr_norm);
50042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	mutex_unlock(&state->mutex);
50142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
50242752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	return IRQ_HANDLED;
50342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors}
50442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
505bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vagastatic int init_device(struct i2c_client *client, struct adv7180_state *state)
5066789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors{
5076789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	int ret;
5086789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
5096789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	/* Initialize adv7180 */
51042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	/* Enable autodetection */
511bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	if (state->autodetect) {
512bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		ret =
513bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
514bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga				ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
515bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga					      | state->input);
516bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		if (ret < 0)
517bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga			return ret;
51842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
519bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		ret =
520bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		    i2c_smbus_write_byte_data(client,
521bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga					      ADV7180_AUTODETECT_ENABLE_REG,
522bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga					      ADV7180_AUTODETECT_DEFAULT);
523bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		if (ret < 0)
524bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga			return ret;
525bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	} else {
526bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		ret = v4l2_std_to_adv7180(state->curr_norm);
527bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		if (ret < 0)
528bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga			return ret;
52942752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
530bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		ret =
531bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		    i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
532bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga					      ret | state->input);
533bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		if (ret < 0)
534bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga			return ret;
535bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
536bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	}
53742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	/* ITU-R BT.656-4 compatible */
53842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	ret = i2c_smbus_write_byte_data(client,
539bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga			ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
540bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga			ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
54142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	if (ret < 0)
542bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		return ret;
543bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
544bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	/* Manually set V bit end position in NTSC mode */
545bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	ret = i2c_smbus_write_byte_data(client,
546bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga					ADV7180_NTSC_V_BIT_END_REG,
547bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga					ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
548bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	if (ret < 0)
549bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		return ret;
55042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
55142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	/* read current norm */
55242752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	__adv7180_status(client, NULL, &state->curr_norm);
55342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
55442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	/* register for interrupts */
55542752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	if (state->irq > 0) {
5560c25534d456535a879aba482dc14795213312514Lars-Peter Clausen		ret = request_threaded_irq(state->irq, NULL, adv7180_irq,
5570c25534d456535a879aba482dc14795213312514Lars-Peter Clausen					   IRQF_ONESHOT, KBUILD_MODNAME, state);
55842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		if (ret)
559bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga			return ret;
56042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
56142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
562bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga						ADV7180_ADI_CTRL_IRQ_SPACE);
56342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		if (ret < 0)
564df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshilov			goto err;
56542752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
56642752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		/* config the Interrupt pin to be active low */
56742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
568bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga						ADV7180_ICONF1_ACTIVE_LOW |
569bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga						ADV7180_ICONF1_PSYNC_ONLY);
57042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		if (ret < 0)
571df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshilov			goto err;
57242752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
57342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
57442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		if (ret < 0)
575df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshilov			goto err;
57642752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
57742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
57842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		if (ret < 0)
579df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshilov			goto err;
58042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
58142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		/* enable AD change interrupts interrupts */
58242752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
583bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga						ADV7180_IRQ3_AD_CHANGE);
58442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		if (ret < 0)
585df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshilov			goto err;
58642752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
58742752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
58842752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		if (ret < 0)
589df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshilov			goto err;
59042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
59142752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
592bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga						0);
59342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		if (ret < 0)
594df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshilov			goto err;
5956789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	}
5966789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
597bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	return 0;
598df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshilov
599df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshiloverr:
600df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshilov	free_irq(state->irq, state);
601df065b373f882c4efc396afa1f31cd8afedab356Alexey Khoroshilov	return ret;
602bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga}
603bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
6044c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartmanstatic int adv7180_probe(struct i2c_client *client,
6054c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartman			 const struct i2c_device_id *id)
606bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga{
607bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	struct adv7180_state *state;
608bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	struct v4l2_subdev *sd;
609bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	int ret;
610bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
611bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	/* Check if the adapter supports the needed features */
612bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
613bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		return -EIO;
614bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
615bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	v4l_info(client, "chip found @ 0x%02x (%s)\n",
616bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		 client->addr, client->adapter->name);
617bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
618c02b211df6fc54e51ee554c27a6736a11255a764Laurent Pinchart	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
619bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	if (state == NULL) {
620bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		ret = -ENOMEM;
621bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		goto err;
622bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	}
623bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
624bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	state->irq = client->irq;
625bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	mutex_init(&state->mutex);
626bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	state->autodetect = true;
627e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	state->powered = true;
628bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	state->input = 0;
629bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	sd = &state->sd;
630bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
631bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
632c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	ret = adv7180_init_controls(state);
633c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	if (ret)
634bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		goto err_unreg_subdev;
635c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	ret = init_device(client, state);
636c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	if (ret)
637c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga		goto err_free_ctrl;
638fa5b7945aefdbcd4419f0b8872ce67866d8071e3Lars-Peter Clausen
639fa5b7945aefdbcd4419f0b8872ce67866d8071e3Lars-Peter Clausen	ret = v4l2_async_register_subdev(sd);
640fa5b7945aefdbcd4419f0b8872ce67866d8071e3Lars-Peter Clausen	if (ret)
641fa5b7945aefdbcd4419f0b8872ce67866d8071e3Lars-Peter Clausen		goto err_free_irq;
642fa5b7945aefdbcd4419f0b8872ce67866d8071e3Lars-Peter Clausen
6436789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	return 0;
64442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
645fa5b7945aefdbcd4419f0b8872ce67866d8071e3Lars-Peter Clausenerr_free_irq:
646fa5b7945aefdbcd4419f0b8872ce67866d8071e3Lars-Peter Clausen	if (state->irq > 0)
647fa5b7945aefdbcd4419f0b8872ce67866d8071e3Lars-Peter Clausen		free_irq(client->irq, state);
648c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vagaerr_free_ctrl:
649c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	adv7180_exit_controls(state);
65042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjforserr_unreg_subdev:
651297a0ae32bf84c8ae135971eb21f18ee5f4ca3eaLars-Peter Clausen	mutex_destroy(&state->mutex);
65242752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjforserr:
65342752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	return ret;
6546789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors}
6556789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
6564c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartmanstatic int adv7180_remove(struct i2c_client *client)
6576789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors{
6586789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	struct v4l2_subdev *sd = i2c_get_clientdata(client);
65942752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors	struct adv7180_state *state = to_state(sd);
66042752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors
661fa5b7945aefdbcd4419f0b8872ce67866d8071e3Lars-Peter Clausen	v4l2_async_unregister_subdev(sd);
662fa5b7945aefdbcd4419f0b8872ce67866d8071e3Lars-Peter Clausen
6630c25534d456535a879aba482dc14795213312514Lars-Peter Clausen	if (state->irq > 0)
66442752f7a3f4afbabb513d5769c590e9abe2d0cd6Richard Röjfors		free_irq(client->irq, state);
6656789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
666b13f4af25c0a36d74a69f7d30e2a28fa941e99b5Lars-Peter Clausen	adv7180_exit_controls(state);
667297a0ae32bf84c8ae135971eb21f18ee5f4ca3eaLars-Peter Clausen	mutex_destroy(&state->mutex);
6686789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	return 0;
6696789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors}
6706789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
6716789cb5230f8b06271b6a89ace20449af14be303Richard Röjforsstatic const struct i2c_device_id adv7180_id[] = {
672c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga	{KBUILD_MODNAME, 0},
6736789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	{},
6746789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors};
6756789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
676cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausen#ifdef CONFIG_PM_SLEEP
677cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausenstatic int adv7180_suspend(struct device *dev)
678bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga{
679cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausen	struct i2c_client *client = to_i2c_client(dev);
680e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	struct v4l2_subdev *sd = i2c_get_clientdata(client);
681e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	struct adv7180_state *state = to_state(sd);
682bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
683e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	return adv7180_set_power(state, client, false);
684bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga}
685bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
686cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausenstatic int adv7180_resume(struct device *dev)
687bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga{
688cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausen	struct i2c_client *client = to_i2c_client(dev);
689bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	struct v4l2_subdev *sd = i2c_get_clientdata(client);
690bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	struct adv7180_state *state = to_state(sd);
691bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	int ret;
692bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
693e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	if (state->powered) {
694e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen		ret = adv7180_set_power(state, client, true);
695e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen		if (ret)
696e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen			return ret;
697e246c3332daa885e911630922ee08c7956dfea0eLars-Peter Clausen	}
698bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	ret = init_device(client, state);
699bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	if (ret < 0)
700bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		return ret;
701bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	return 0;
702bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga}
703cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausen
704cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausenstatic SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
705cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausen#define ADV7180_PM_OPS (&adv7180_pm_ops)
706cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausen
707cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausen#else
708cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausen#define ADV7180_PM_OPS NULL
709bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga#endif
710bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga
7116789cb5230f8b06271b6a89ace20449af14be303Richard RöjforsMODULE_DEVICE_TABLE(i2c, adv7180_id);
7126789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
7136789cb5230f8b06271b6a89ace20449af14be303Richard Röjforsstatic struct i2c_driver adv7180_driver = {
7146789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors	.driver = {
715bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		   .owner = THIS_MODULE,
716c9fbedddc2b9cdf1b1a4a4053f52a629c0daa9a0Federico Vaga		   .name = KBUILD_MODNAME,
717cc1088dc0b92723c5e2e4cb5098dfa84a39afaedLars-Peter Clausen		   .pm = ADV7180_PM_OPS,
718bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga		   },
719bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	.probe = adv7180_probe,
7204c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartman	.remove = adv7180_remove,
721bca7ad1a332a0754860bdd57b258f8e9ee5eb2a5Federico Vaga	.id_table = adv7180_id,
7226789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors};
7236789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
724c6e8d86fffd8edf1bfccbd441b1812ee919fe3d5Axel Linmodule_i2c_driver(adv7180_driver);
7256789cb5230f8b06271b6a89ace20449af14be303Richard Röjfors
7266789cb5230f8b06271b6a89ace20449af14be303Richard RöjforsMODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
7276789cb5230f8b06271b6a89ace20449af14be303Richard RöjforsMODULE_AUTHOR("Mocean Laboratories");
7286789cb5230f8b06271b6a89ace20449af14be303Richard RöjforsMODULE_LICENSE("GPL v2");
729