blob: 623cec5c5eb95c6e99babf0cec9ab1bdc29ef9b7 [file] [log] [blame]
Richard Röjfors6789cb52009-09-18 21:17:20 -03001/*
2 * adv7180.c Analog Devices ADV7180 video decoder driver
3 * Copyright (c) 2009 Intel Corporation
Vladimir Barinovcccb83f2013-05-29 14:50:57 -03004 * Copyright (C) 2013 Cogent Embedded, Inc.
5 * Copyright (C) 2013 Renesas Solutions Corp.
Richard Röjfors6789cb52009-09-18 21:17:20 -03006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/errno.h>
24#include <linux/kernel.h>
25#include <linux/interrupt.h>
26#include <linux/i2c.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090027#include <linux/slab.h>
Richard Röjfors6789cb52009-09-18 21:17:20 -030028#include <media/v4l2-ioctl.h>
29#include <linux/videodev2.h>
30#include <media/v4l2-device.h>
Federico Vagac9fbedd2012-07-11 11:29:33 -030031#include <media/v4l2-ctrls.h>
Richard Röjfors42752f72009-09-22 06:07:06 -030032#include <linux/mutex.h>
Richard Röjfors6789cb52009-09-18 21:17:20 -030033
Richard Röjforsd3124292009-09-22 06:05:42 -030034#define ADV7180_INPUT_CONTROL_REG 0x00
35#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00
36#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
37#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20
38#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30
39#define ADV7180_INPUT_CONTROL_NTSC_J 0x40
40#define ADV7180_INPUT_CONTROL_NTSC_M 0x50
41#define ADV7180_INPUT_CONTROL_PAL60 0x60
42#define ADV7180_INPUT_CONTROL_NTSC_443 0x70
43#define ADV7180_INPUT_CONTROL_PAL_BG 0x80
44#define ADV7180_INPUT_CONTROL_PAL_N 0x90
45#define ADV7180_INPUT_CONTROL_PAL_M 0xa0
46#define ADV7180_INPUT_CONTROL_PAL_M_PED 0xb0
47#define ADV7180_INPUT_CONTROL_PAL_COMB_N 0xc0
48#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED 0xd0
49#define ADV7180_INPUT_CONTROL_PAL_SECAM 0xe0
50#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED 0xf0
Federico Vagabca7ad12012-04-12 12:39:36 -030051#define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f
Richard Röjforsd3124292009-09-22 06:05:42 -030052
Richard Röjfors42752f72009-09-22 06:07:06 -030053#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG 0x04
54#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5
Richard Röjfors6789cb52009-09-18 21:17:20 -030055
Richard Röjfors42752f72009-09-22 06:07:06 -030056#define ADV7180_AUTODETECT_ENABLE_REG 0x07
57#define ADV7180_AUTODETECT_DEFAULT 0x7f
Federico Vagac9fbedd2012-07-11 11:29:33 -030058/* Contrast */
Federico Vagabca7ad12012-04-12 12:39:36 -030059#define ADV7180_CON_REG 0x08 /*Unsigned */
Federico Vagac9fbedd2012-07-11 11:29:33 -030060#define ADV7180_CON_MIN 0
61#define ADV7180_CON_DEF 128
62#define ADV7180_CON_MAX 255
63/* Brightness*/
Federico Vagabca7ad12012-04-12 12:39:36 -030064#define ADV7180_BRI_REG 0x0a /*Signed */
Federico Vagac9fbedd2012-07-11 11:29:33 -030065#define ADV7180_BRI_MIN -128
66#define ADV7180_BRI_DEF 0
67#define ADV7180_BRI_MAX 127
68/* Hue */
Federico Vagabca7ad12012-04-12 12:39:36 -030069#define ADV7180_HUE_REG 0x0b /*Signed, inverted */
Federico Vagac9fbedd2012-07-11 11:29:33 -030070#define ADV7180_HUE_MIN -127
71#define ADV7180_HUE_DEF 0
72#define ADV7180_HUE_MAX 128
Federico Vagabca7ad12012-04-12 12:39:36 -030073
Richard Röjfors42752f72009-09-22 06:07:06 -030074#define ADV7180_ADI_CTRL_REG 0x0e
75#define ADV7180_ADI_CTRL_IRQ_SPACE 0x20
Richard Röjfors6789cb52009-09-18 21:17:20 -030076
Federico Vagabca7ad12012-04-12 12:39:36 -030077#define ADV7180_PWR_MAN_REG 0x0f
78#define ADV7180_PWR_MAN_ON 0x04
79#define ADV7180_PWR_MAN_OFF 0x24
80#define ADV7180_PWR_MAN_RES 0x80
81
Richard Röjforsd3124292009-09-22 06:05:42 -030082#define ADV7180_STATUS1_REG 0x10
83#define ADV7180_STATUS1_IN_LOCK 0x01
84#define ADV7180_STATUS1_AUTOD_MASK 0x70
Richard Röjfors6789cb52009-09-18 21:17:20 -030085#define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00
86#define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10
87#define ADV7180_STATUS1_AUTOD_PAL_M 0x20
88#define ADV7180_STATUS1_AUTOD_PAL_60 0x30
89#define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40
90#define ADV7180_STATUS1_AUTOD_SECAM 0x50
91#define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60
92#define ADV7180_STATUS1_AUTOD_SECAM_525 0x70
93
94#define ADV7180_IDENT_REG 0x11
95#define ADV7180_ID_7180 0x18
96
Richard Röjfors42752f72009-09-22 06:07:06 -030097#define ADV7180_ICONF1_ADI 0x40
98#define ADV7180_ICONF1_ACTIVE_LOW 0x01
99#define ADV7180_ICONF1_PSYNC_ONLY 0x10
100#define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0
Federico Vagac9fbedd2012-07-11 11:29:33 -0300101/* Saturation */
Federico Vagabca7ad12012-04-12 12:39:36 -0300102#define ADV7180_SD_SAT_CB_REG 0xe3 /*Unsigned */
103#define ADV7180_SD_SAT_CR_REG 0xe4 /*Unsigned */
Federico Vagac9fbedd2012-07-11 11:29:33 -0300104#define ADV7180_SAT_MIN 0
105#define ADV7180_SAT_DEF 128
106#define ADV7180_SAT_MAX 255
Federico Vagabca7ad12012-04-12 12:39:36 -0300107
Richard Röjfors42752f72009-09-22 06:07:06 -0300108#define ADV7180_IRQ1_LOCK 0x01
109#define ADV7180_IRQ1_UNLOCK 0x02
110#define ADV7180_ISR1_ADI 0x42
111#define ADV7180_ICR1_ADI 0x43
112#define ADV7180_IMR1_ADI 0x44
113#define ADV7180_IMR2_ADI 0x48
114#define ADV7180_IRQ3_AD_CHANGE 0x08
115#define ADV7180_ISR3_ADI 0x4A
116#define ADV7180_ICR3_ADI 0x4B
117#define ADV7180_IMR3_ADI 0x4C
118#define ADV7180_IMR4_ADI 0x50
Richard Röjfors6789cb52009-09-18 21:17:20 -0300119
Federico Vagabca7ad12012-04-12 12:39:36 -0300120#define ADV7180_NTSC_V_BIT_END_REG 0xE6
121#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F
122
Richard Röjfors6789cb52009-09-18 21:17:20 -0300123struct adv7180_state {
Federico Vagac9fbedd2012-07-11 11:29:33 -0300124 struct v4l2_ctrl_handler ctrl_hdl;
Richard Röjforsc277b602009-09-22 06:06:34 -0300125 struct v4l2_subdev sd;
Richard Röjfors42752f72009-09-22 06:07:06 -0300126 struct mutex mutex; /* mutual excl. when accessing chip */
127 int irq;
Richard Röjforsc277b602009-09-22 06:06:34 -0300128 v4l2_std_id curr_norm;
129 bool autodetect;
Federico Vagabca7ad12012-04-12 12:39:36 -0300130 u8 input;
Richard Röjfors6789cb52009-09-18 21:17:20 -0300131};
Federico Vagac9fbedd2012-07-11 11:29:33 -0300132#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
133 struct adv7180_state, \
134 ctrl_hdl)->sd)
Richard Röjfors6789cb52009-09-18 21:17:20 -0300135
Richard Röjforsd3124292009-09-22 06:05:42 -0300136static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
Richard Röjfors6789cb52009-09-18 21:17:20 -0300137{
Vladimir Barinovb294a192013-04-11 18:06:46 -0300138 /* in case V4L2_IN_ST_NO_SIGNAL */
139 if (!(status1 & ADV7180_STATUS1_IN_LOCK))
140 return V4L2_STD_UNKNOWN;
141
Richard Röjfors6789cb52009-09-18 21:17:20 -0300142 switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
143 case ADV7180_STATUS1_AUTOD_NTSM_M_J:
Richard Röjforsd3124292009-09-22 06:05:42 -0300144 return V4L2_STD_NTSC;
Richard Röjfors6789cb52009-09-18 21:17:20 -0300145 case ADV7180_STATUS1_AUTOD_NTSC_4_43:
146 return V4L2_STD_NTSC_443;
147 case ADV7180_STATUS1_AUTOD_PAL_M:
148 return V4L2_STD_PAL_M;
149 case ADV7180_STATUS1_AUTOD_PAL_60:
150 return V4L2_STD_PAL_60;
151 case ADV7180_STATUS1_AUTOD_PAL_B_G:
152 return V4L2_STD_PAL;
153 case ADV7180_STATUS1_AUTOD_SECAM:
154 return V4L2_STD_SECAM;
155 case ADV7180_STATUS1_AUTOD_PAL_COMB:
156 return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
157 case ADV7180_STATUS1_AUTOD_SECAM_525:
158 return V4L2_STD_SECAM;
159 default:
160 return V4L2_STD_UNKNOWN;
161 }
162}
163
Richard Röjforsc277b602009-09-22 06:06:34 -0300164static int v4l2_std_to_adv7180(v4l2_std_id std)
165{
166 if (std == V4L2_STD_PAL_60)
167 return ADV7180_INPUT_CONTROL_PAL60;
168 if (std == V4L2_STD_NTSC_443)
169 return ADV7180_INPUT_CONTROL_NTSC_443;
170 if (std == V4L2_STD_PAL_N)
171 return ADV7180_INPUT_CONTROL_PAL_N;
172 if (std == V4L2_STD_PAL_M)
173 return ADV7180_INPUT_CONTROL_PAL_M;
174 if (std == V4L2_STD_PAL_Nc)
175 return ADV7180_INPUT_CONTROL_PAL_COMB_N;
176
177 if (std & V4L2_STD_PAL)
178 return ADV7180_INPUT_CONTROL_PAL_BG;
179 if (std & V4L2_STD_NTSC)
180 return ADV7180_INPUT_CONTROL_NTSC_M;
181 if (std & V4L2_STD_SECAM)
182 return ADV7180_INPUT_CONTROL_PAL_SECAM;
183
184 return -EINVAL;
185}
186
Richard Röjforsd3124292009-09-22 06:05:42 -0300187static u32 adv7180_status_to_v4l2(u8 status1)
188{
189 if (!(status1 & ADV7180_STATUS1_IN_LOCK))
190 return V4L2_IN_ST_NO_SIGNAL;
191
192 return 0;
193}
194
195static int __adv7180_status(struct i2c_client *client, u32 *status,
Federico Vagabca7ad12012-04-12 12:39:36 -0300196 v4l2_std_id *std)
Richard Röjforsd3124292009-09-22 06:05:42 -0300197{
198 int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
199
200 if (status1 < 0)
201 return status1;
202
203 if (status)
204 *status = adv7180_status_to_v4l2(status1);
205 if (std)
206 *std = adv7180_std_to_v4l2(status1);
207
208 return 0;
209}
210
Richard Röjfors6789cb52009-09-18 21:17:20 -0300211static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
212{
213 return container_of(sd, struct adv7180_state, sd);
214}
215
216static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
217{
Richard Röjforsc277b602009-09-22 06:06:34 -0300218 struct adv7180_state *state = to_state(sd);
Richard Röjfors42752f72009-09-22 06:07:06 -0300219 int err = mutex_lock_interruptible(&state->mutex);
220 if (err)
221 return err;
Richard Röjforsc277b602009-09-22 06:06:34 -0300222
Richard Röjfors42752f72009-09-22 06:07:06 -0300223 /* when we are interrupt driven we know the state */
224 if (!state->autodetect || state->irq > 0)
Richard Röjforsc277b602009-09-22 06:06:34 -0300225 *std = state->curr_norm;
226 else
227 err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
228
Richard Röjfors42752f72009-09-22 06:07:06 -0300229 mutex_unlock(&state->mutex);
Richard Röjforsc277b602009-09-22 06:06:34 -0300230 return err;
Richard Röjforsd3124292009-09-22 06:05:42 -0300231}
Richard Röjfors6789cb52009-09-18 21:17:20 -0300232
Federico Vagabca7ad12012-04-12 12:39:36 -0300233static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
234 u32 output, u32 config)
235{
236 struct adv7180_state *state = to_state(sd);
237 int ret = mutex_lock_interruptible(&state->mutex);
238 struct i2c_client *client = v4l2_get_subdevdata(sd);
239
240 if (ret)
241 return ret;
242
Federico Vagac9fbedd2012-07-11 11:29:33 -0300243 /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
Federico Vagabca7ad12012-04-12 12:39:36 -0300244 * all inputs and let the card driver take care of validation
245 */
246 if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
247 goto out;
248
249 ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG);
250
251 if (ret < 0)
252 goto out;
253
254 ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
255 ret = i2c_smbus_write_byte_data(client,
256 ADV7180_INPUT_CONTROL_REG, ret | input);
257 state->input = input;
258out:
259 mutex_unlock(&state->mutex);
260 return ret;
261}
262
Richard Röjforsd3124292009-09-22 06:05:42 -0300263static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
264{
Richard Röjfors42752f72009-09-22 06:07:06 -0300265 struct adv7180_state *state = to_state(sd);
266 int ret = mutex_lock_interruptible(&state->mutex);
267 if (ret)
268 return ret;
269
270 ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
271 mutex_unlock(&state->mutex);
272 return ret;
Richard Röjfors6789cb52009-09-18 21:17:20 -0300273}
274
Richard Röjforsc277b602009-09-22 06:06:34 -0300275static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
276{
277 struct adv7180_state *state = to_state(sd);
278 struct i2c_client *client = v4l2_get_subdevdata(sd);
Richard Röjfors42752f72009-09-22 06:07:06 -0300279 int ret = mutex_lock_interruptible(&state->mutex);
280 if (ret)
281 return ret;
Richard Röjforsc277b602009-09-22 06:06:34 -0300282
283 /* all standards -> autodetect */
284 if (std == V4L2_STD_ALL) {
Federico Vagabca7ad12012-04-12 12:39:36 -0300285 ret =
286 i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
287 ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
288 | state->input);
Richard Röjforsc277b602009-09-22 06:06:34 -0300289 if (ret < 0)
290 goto out;
291
Richard Röjfors42752f72009-09-22 06:07:06 -0300292 __adv7180_status(client, NULL, &state->curr_norm);
Richard Röjforsc277b602009-09-22 06:06:34 -0300293 state->autodetect = true;
294 } else {
295 ret = v4l2_std_to_adv7180(std);
296 if (ret < 0)
297 goto out;
298
299 ret = i2c_smbus_write_byte_data(client,
Federico Vagabca7ad12012-04-12 12:39:36 -0300300 ADV7180_INPUT_CONTROL_REG,
301 ret | state->input);
Richard Röjforsc277b602009-09-22 06:06:34 -0300302 if (ret < 0)
303 goto out;
304
305 state->curr_norm = std;
306 state->autodetect = false;
307 }
308 ret = 0;
309out:
Richard Röjfors42752f72009-09-22 06:07:06 -0300310 mutex_unlock(&state->mutex);
Richard Röjforsc277b602009-09-22 06:06:34 -0300311 return ret;
312}
313
Federico Vagac9fbedd2012-07-11 11:29:33 -0300314static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
Federico Vagabca7ad12012-04-12 12:39:36 -0300315{
Federico Vagac9fbedd2012-07-11 11:29:33 -0300316 struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
Federico Vagabca7ad12012-04-12 12:39:36 -0300317 struct adv7180_state *state = to_state(sd);
318 struct i2c_client *client = v4l2_get_subdevdata(sd);
319 int ret = mutex_lock_interruptible(&state->mutex);
Federico Vagac9fbedd2012-07-11 11:29:33 -0300320 int val;
321
Federico Vagabca7ad12012-04-12 12:39:36 -0300322 if (ret)
323 return ret;
Federico Vagac9fbedd2012-07-11 11:29:33 -0300324 val = ctrl->val;
Federico Vagabca7ad12012-04-12 12:39:36 -0300325 switch (ctrl->id) {
326 case V4L2_CID_BRIGHTNESS:
Federico Vagac9fbedd2012-07-11 11:29:33 -0300327 ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, val);
Federico Vagabca7ad12012-04-12 12:39:36 -0300328 break;
329 case V4L2_CID_HUE:
Federico Vagabca7ad12012-04-12 12:39:36 -0300330 /*Hue is inverted according to HSL chart */
Federico Vagac9fbedd2012-07-11 11:29:33 -0300331 ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, -val);
Federico Vagabca7ad12012-04-12 12:39:36 -0300332 break;
333 case V4L2_CID_CONTRAST:
Federico Vagac9fbedd2012-07-11 11:29:33 -0300334 ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, val);
Federico Vagabca7ad12012-04-12 12:39:36 -0300335 break;
336 case V4L2_CID_SATURATION:
Federico Vagabca7ad12012-04-12 12:39:36 -0300337 /*
338 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
339 *Let's not confuse the user, everybody understands saturation
340 */
Federico Vagac9fbedd2012-07-11 11:29:33 -0300341 ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG,
342 val);
Federico Vagabca7ad12012-04-12 12:39:36 -0300343 if (ret < 0)
344 break;
Federico Vagac9fbedd2012-07-11 11:29:33 -0300345 ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG,
346 val);
Federico Vagabca7ad12012-04-12 12:39:36 -0300347 break;
348 default:
349 ret = -EINVAL;
350 }
351
352 mutex_unlock(&state->mutex);
353 return ret;
354}
355
Federico Vagac9fbedd2012-07-11 11:29:33 -0300356static const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
357 .s_ctrl = adv7180_s_ctrl,
358};
359
360static int adv7180_init_controls(struct adv7180_state *state)
361{
362 v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
363
364 v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
365 V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN,
366 ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF);
367 v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
368 V4L2_CID_CONTRAST, ADV7180_CON_MIN,
369 ADV7180_CON_MAX, 1, ADV7180_CON_DEF);
370 v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
371 V4L2_CID_SATURATION, ADV7180_SAT_MIN,
372 ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF);
373 v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
374 V4L2_CID_HUE, ADV7180_HUE_MIN,
375 ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
376 state->sd.ctrl_handler = &state->ctrl_hdl;
377 if (state->ctrl_hdl.error) {
378 int err = state->ctrl_hdl.error;
379
380 v4l2_ctrl_handler_free(&state->ctrl_hdl);
381 return err;
382 }
383 v4l2_ctrl_handler_setup(&state->ctrl_hdl);
384
385 return 0;
386}
387static void adv7180_exit_controls(struct adv7180_state *state)
388{
389 v4l2_ctrl_handler_free(&state->ctrl_hdl);
390}
391
Vladimir Barinovcccb83f2013-05-29 14:50:57 -0300392static int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
393 enum v4l2_mbus_pixelcode *code)
394{
395 if (index > 0)
396 return -EINVAL;
397
398 *code = V4L2_MBUS_FMT_YUYV8_2X8;
399
400 return 0;
401}
402
403static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
404 struct v4l2_mbus_framefmt *fmt)
405{
406 struct adv7180_state *state = to_state(sd);
407
408 fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
409 fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
410 fmt->field = V4L2_FIELD_INTERLACED;
411 fmt->width = 720;
412 fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
413
414 return 0;
415}
416
417static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
418 struct v4l2_mbus_config *cfg)
419{
420 /*
421 * The ADV7180 sensor supports BT.601/656 output modes.
422 * The BT.656 is default and not yet configurable by s/w.
423 */
424 cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
425 V4L2_MBUS_DATA_ACTIVE_HIGH;
426 cfg->type = V4L2_MBUS_BT656;
427
428 return 0;
429}
430
Richard Röjfors6789cb52009-09-18 21:17:20 -0300431static const struct v4l2_subdev_video_ops adv7180_video_ops = {
432 .querystd = adv7180_querystd,
Richard Röjforsd3124292009-09-22 06:05:42 -0300433 .g_input_status = adv7180_g_input_status,
Federico Vagabca7ad12012-04-12 12:39:36 -0300434 .s_routing = adv7180_s_routing,
Vladimir Barinovcccb83f2013-05-29 14:50:57 -0300435 .enum_mbus_fmt = adv7180_enum_mbus_fmt,
436 .try_mbus_fmt = adv7180_mbus_fmt,
437 .g_mbus_fmt = adv7180_mbus_fmt,
438 .s_mbus_fmt = adv7180_mbus_fmt,
439 .g_mbus_config = adv7180_g_mbus_config,
Richard Röjfors6789cb52009-09-18 21:17:20 -0300440};
441
442static const struct v4l2_subdev_core_ops adv7180_core_ops = {
Richard Röjforsc277b602009-09-22 06:06:34 -0300443 .s_std = adv7180_s_std,
Richard Röjfors6789cb52009-09-18 21:17:20 -0300444};
445
446static const struct v4l2_subdev_ops adv7180_ops = {
447 .core = &adv7180_core_ops,
448 .video = &adv7180_video_ops,
449};
450
Lars-Peter Clausen0c255342014-03-07 13:14:31 -0300451static irqreturn_t adv7180_irq(int irq, void *devid)
Richard Röjfors42752f72009-09-22 06:07:06 -0300452{
Lars-Peter Clausen0c255342014-03-07 13:14:31 -0300453 struct adv7180_state *state = devid;
Richard Röjfors42752f72009-09-22 06:07:06 -0300454 struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
455 u8 isr3;
456
457 mutex_lock(&state->mutex);
458 i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
Federico Vagabca7ad12012-04-12 12:39:36 -0300459 ADV7180_ADI_CTRL_IRQ_SPACE);
Richard Röjfors42752f72009-09-22 06:07:06 -0300460 isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
461 /* clear */
462 i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
463 i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
464
465 if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
466 __adv7180_status(client, NULL, &state->curr_norm);
467 mutex_unlock(&state->mutex);
468
Richard Röjfors42752f72009-09-22 06:07:06 -0300469 return IRQ_HANDLED;
470}
471
Federico Vagabca7ad12012-04-12 12:39:36 -0300472static int init_device(struct i2c_client *client, struct adv7180_state *state)
473{
474 int ret;
475
476 /* Initialize adv7180 */
477 /* Enable autodetection */
478 if (state->autodetect) {
479 ret =
480 i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
481 ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
482 | state->input);
483 if (ret < 0)
484 return ret;
485
486 ret =
487 i2c_smbus_write_byte_data(client,
488 ADV7180_AUTODETECT_ENABLE_REG,
489 ADV7180_AUTODETECT_DEFAULT);
490 if (ret < 0)
491 return ret;
492 } else {
493 ret = v4l2_std_to_adv7180(state->curr_norm);
494 if (ret < 0)
495 return ret;
496
497 ret =
498 i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
499 ret | state->input);
500 if (ret < 0)
501 return ret;
502
503 }
504 /* ITU-R BT.656-4 compatible */
505 ret = i2c_smbus_write_byte_data(client,
506 ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
507 ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
508 if (ret < 0)
509 return ret;
510
511 /* Manually set V bit end position in NTSC mode */
512 ret = i2c_smbus_write_byte_data(client,
513 ADV7180_NTSC_V_BIT_END_REG,
514 ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
515 if (ret < 0)
516 return ret;
517
518 /* read current norm */
519 __adv7180_status(client, NULL, &state->curr_norm);
520
521 /* register for interrupts */
522 if (state->irq > 0) {
Lars-Peter Clausen0c255342014-03-07 13:14:31 -0300523 ret = request_threaded_irq(state->irq, NULL, adv7180_irq,
524 IRQF_ONESHOT, KBUILD_MODNAME, state);
Federico Vagabca7ad12012-04-12 12:39:36 -0300525 if (ret)
526 return ret;
527
528 ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
529 ADV7180_ADI_CTRL_IRQ_SPACE);
530 if (ret < 0)
531 return ret;
532
533 /* config the Interrupt pin to be active low */
534 ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
535 ADV7180_ICONF1_ACTIVE_LOW |
536 ADV7180_ICONF1_PSYNC_ONLY);
537 if (ret < 0)
538 return ret;
539
540 ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
541 if (ret < 0)
542 return ret;
543
544 ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
545 if (ret < 0)
546 return ret;
547
548 /* enable AD change interrupts interrupts */
549 ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
550 ADV7180_IRQ3_AD_CHANGE);
551 if (ret < 0)
552 return ret;
553
554 ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
555 if (ret < 0)
556 return ret;
557
558 ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
559 0);
560 if (ret < 0)
561 return ret;
562 }
563
Federico Vagabca7ad12012-04-12 12:39:36 -0300564 return 0;
565}
Richard Röjfors6789cb52009-09-18 21:17:20 -0300566
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -0800567static int adv7180_probe(struct i2c_client *client,
568 const struct i2c_device_id *id)
Richard Röjfors6789cb52009-09-18 21:17:20 -0300569{
570 struct adv7180_state *state;
571 struct v4l2_subdev *sd;
572 int ret;
573
574 /* Check if the adapter supports the needed features */
575 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
576 return -EIO;
577
578 v4l_info(client, "chip found @ 0x%02x (%s)\n",
Federico Vagabca7ad12012-04-12 12:39:36 -0300579 client->addr, client->adapter->name);
Richard Röjfors6789cb52009-09-18 21:17:20 -0300580
Laurent Pinchartc02b2112013-05-02 08:29:43 -0300581 state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
Richard Röjfors42752f72009-09-22 06:07:06 -0300582 if (state == NULL) {
583 ret = -ENOMEM;
584 goto err;
585 }
586
587 state->irq = client->irq;
Richard Röjfors42752f72009-09-22 06:07:06 -0300588 mutex_init(&state->mutex);
Richard Röjforsc277b602009-09-22 06:06:34 -0300589 state->autodetect = true;
Federico Vagabca7ad12012-04-12 12:39:36 -0300590 state->input = 0;
Richard Röjfors6789cb52009-09-18 21:17:20 -0300591 sd = &state->sd;
592 v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
593
Federico Vagac9fbedd2012-07-11 11:29:33 -0300594 ret = adv7180_init_controls(state);
595 if (ret)
Richard Röjfors42752f72009-09-22 06:07:06 -0300596 goto err_unreg_subdev;
Federico Vagac9fbedd2012-07-11 11:29:33 -0300597 ret = init_device(client, state);
598 if (ret)
599 goto err_free_ctrl;
Lars-Peter Clausenfa5b7942014-03-07 13:14:32 -0300600
601 ret = v4l2_async_register_subdev(sd);
602 if (ret)
603 goto err_free_irq;
604
Richard Röjfors6789cb52009-09-18 21:17:20 -0300605 return 0;
Richard Röjfors42752f72009-09-22 06:07:06 -0300606
Lars-Peter Clausenfa5b7942014-03-07 13:14:32 -0300607err_free_irq:
608 if (state->irq > 0)
609 free_irq(client->irq, state);
Federico Vagac9fbedd2012-07-11 11:29:33 -0300610err_free_ctrl:
611 adv7180_exit_controls(state);
Richard Röjfors42752f72009-09-22 06:07:06 -0300612err_unreg_subdev:
Lars-Peter Clausen297a0ae2014-03-07 13:14:27 -0300613 mutex_destroy(&state->mutex);
Richard Röjfors42752f72009-09-22 06:07:06 -0300614err:
Richard Röjfors42752f72009-09-22 06:07:06 -0300615 return ret;
Richard Röjfors6789cb52009-09-18 21:17:20 -0300616}
617
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -0800618static int adv7180_remove(struct i2c_client *client)
Richard Röjfors6789cb52009-09-18 21:17:20 -0300619{
620 struct v4l2_subdev *sd = i2c_get_clientdata(client);
Richard Röjfors42752f72009-09-22 06:07:06 -0300621 struct adv7180_state *state = to_state(sd);
Richard Röjfors6789cb52009-09-18 21:17:20 -0300622
Lars-Peter Clausenfa5b7942014-03-07 13:14:32 -0300623 v4l2_async_unregister_subdev(sd);
624
Lars-Peter Clausen0c255342014-03-07 13:14:31 -0300625 if (state->irq > 0)
Richard Röjfors42752f72009-09-22 06:07:06 -0300626 free_irq(client->irq, state);
Richard Röjfors42752f72009-09-22 06:07:06 -0300627
Richard Röjfors6789cb52009-09-18 21:17:20 -0300628 v4l2_device_unregister_subdev(sd);
Lars-Peter Clausenb13f4af2014-03-07 13:14:28 -0300629 adv7180_exit_controls(state);
Lars-Peter Clausen297a0ae2014-03-07 13:14:27 -0300630 mutex_destroy(&state->mutex);
Richard Röjfors6789cb52009-09-18 21:17:20 -0300631 return 0;
632}
633
634static const struct i2c_device_id adv7180_id[] = {
Federico Vagac9fbedd2012-07-11 11:29:33 -0300635 {KBUILD_MODNAME, 0},
Richard Röjfors6789cb52009-09-18 21:17:20 -0300636 {},
637};
638
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300639#ifdef CONFIG_PM_SLEEP
640static int adv7180_suspend(struct device *dev)
Federico Vagabca7ad12012-04-12 12:39:36 -0300641{
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300642 struct i2c_client *client = to_i2c_client(dev);
Federico Vagabca7ad12012-04-12 12:39:36 -0300643 int ret;
644
645 ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
646 ADV7180_PWR_MAN_OFF);
647 if (ret < 0)
648 return ret;
649 return 0;
650}
651
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300652static int adv7180_resume(struct device *dev)
Federico Vagabca7ad12012-04-12 12:39:36 -0300653{
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300654 struct i2c_client *client = to_i2c_client(dev);
Federico Vagabca7ad12012-04-12 12:39:36 -0300655 struct v4l2_subdev *sd = i2c_get_clientdata(client);
656 struct adv7180_state *state = to_state(sd);
657 int ret;
658
659 ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
660 ADV7180_PWR_MAN_ON);
661 if (ret < 0)
662 return ret;
663 ret = init_device(client, state);
664 if (ret < 0)
665 return ret;
666 return 0;
667}
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300668
669static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
670#define ADV7180_PM_OPS (&adv7180_pm_ops)
671
672#else
673#define ADV7180_PM_OPS NULL
Federico Vagabca7ad12012-04-12 12:39:36 -0300674#endif
675
Richard Röjfors6789cb52009-09-18 21:17:20 -0300676MODULE_DEVICE_TABLE(i2c, adv7180_id);
677
678static struct i2c_driver adv7180_driver = {
679 .driver = {
Federico Vagabca7ad12012-04-12 12:39:36 -0300680 .owner = THIS_MODULE,
Federico Vagac9fbedd2012-07-11 11:29:33 -0300681 .name = KBUILD_MODNAME,
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300682 .pm = ADV7180_PM_OPS,
Federico Vagabca7ad12012-04-12 12:39:36 -0300683 },
684 .probe = adv7180_probe,
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -0800685 .remove = adv7180_remove,
Federico Vagabca7ad12012-04-12 12:39:36 -0300686 .id_table = adv7180_id,
Richard Röjfors6789cb52009-09-18 21:17:20 -0300687};
688
Axel Linc6e8d862012-02-12 06:56:32 -0300689module_i2c_driver(adv7180_driver);
Richard Röjfors6789cb52009-09-18 21:17:20 -0300690
691MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
692MODULE_AUTHOR("Mocean Laboratories");
693MODULE_LICENSE("GPL v2");