blob: ac1cdbe251a330bd943fe6b0b07ebb57f830db36 [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;
Lars-Peter Clausene246c332014-03-10 14:05:39 -0300130 bool powered;
Federico Vagabca7ad12012-04-12 12:39:36 -0300131 u8 input;
Richard Röjfors6789cb52009-09-18 21:17:20 -0300132};
Federico Vagac9fbedd2012-07-11 11:29:33 -0300133#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
134 struct adv7180_state, \
135 ctrl_hdl)->sd)
Richard Röjfors6789cb52009-09-18 21:17:20 -0300136
Richard Röjforsd3124292009-09-22 06:05:42 -0300137static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
Richard Röjfors6789cb52009-09-18 21:17:20 -0300138{
Vladimir Barinovb294a192013-04-11 18:06:46 -0300139 /* in case V4L2_IN_ST_NO_SIGNAL */
140 if (!(status1 & ADV7180_STATUS1_IN_LOCK))
141 return V4L2_STD_UNKNOWN;
142
Richard Röjfors6789cb52009-09-18 21:17:20 -0300143 switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
144 case ADV7180_STATUS1_AUTOD_NTSM_M_J:
Richard Röjforsd3124292009-09-22 06:05:42 -0300145 return V4L2_STD_NTSC;
Richard Röjfors6789cb52009-09-18 21:17:20 -0300146 case ADV7180_STATUS1_AUTOD_NTSC_4_43:
147 return V4L2_STD_NTSC_443;
148 case ADV7180_STATUS1_AUTOD_PAL_M:
149 return V4L2_STD_PAL_M;
150 case ADV7180_STATUS1_AUTOD_PAL_60:
151 return V4L2_STD_PAL_60;
152 case ADV7180_STATUS1_AUTOD_PAL_B_G:
153 return V4L2_STD_PAL;
154 case ADV7180_STATUS1_AUTOD_SECAM:
155 return V4L2_STD_SECAM;
156 case ADV7180_STATUS1_AUTOD_PAL_COMB:
157 return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
158 case ADV7180_STATUS1_AUTOD_SECAM_525:
159 return V4L2_STD_SECAM;
160 default:
161 return V4L2_STD_UNKNOWN;
162 }
163}
164
Richard Röjforsc277b602009-09-22 06:06:34 -0300165static int v4l2_std_to_adv7180(v4l2_std_id std)
166{
167 if (std == V4L2_STD_PAL_60)
168 return ADV7180_INPUT_CONTROL_PAL60;
169 if (std == V4L2_STD_NTSC_443)
170 return ADV7180_INPUT_CONTROL_NTSC_443;
171 if (std == V4L2_STD_PAL_N)
172 return ADV7180_INPUT_CONTROL_PAL_N;
173 if (std == V4L2_STD_PAL_M)
174 return ADV7180_INPUT_CONTROL_PAL_M;
175 if (std == V4L2_STD_PAL_Nc)
176 return ADV7180_INPUT_CONTROL_PAL_COMB_N;
177
178 if (std & V4L2_STD_PAL)
179 return ADV7180_INPUT_CONTROL_PAL_BG;
180 if (std & V4L2_STD_NTSC)
181 return ADV7180_INPUT_CONTROL_NTSC_M;
182 if (std & V4L2_STD_SECAM)
183 return ADV7180_INPUT_CONTROL_PAL_SECAM;
184
185 return -EINVAL;
186}
187
Richard Röjforsd3124292009-09-22 06:05:42 -0300188static u32 adv7180_status_to_v4l2(u8 status1)
189{
190 if (!(status1 & ADV7180_STATUS1_IN_LOCK))
191 return V4L2_IN_ST_NO_SIGNAL;
192
193 return 0;
194}
195
196static int __adv7180_status(struct i2c_client *client, u32 *status,
Federico Vagabca7ad12012-04-12 12:39:36 -0300197 v4l2_std_id *std)
Richard Röjforsd3124292009-09-22 06:05:42 -0300198{
199 int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
200
201 if (status1 < 0)
202 return status1;
203
204 if (status)
205 *status = adv7180_status_to_v4l2(status1);
206 if (std)
207 *std = adv7180_std_to_v4l2(status1);
208
209 return 0;
210}
211
Richard Röjfors6789cb52009-09-18 21:17:20 -0300212static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
213{
214 return container_of(sd, struct adv7180_state, sd);
215}
216
217static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
218{
Richard Röjforsc277b602009-09-22 06:06:34 -0300219 struct adv7180_state *state = to_state(sd);
Richard Röjfors42752f72009-09-22 06:07:06 -0300220 int err = mutex_lock_interruptible(&state->mutex);
221 if (err)
222 return err;
Richard Röjforsc277b602009-09-22 06:06:34 -0300223
Richard Röjfors42752f72009-09-22 06:07:06 -0300224 /* when we are interrupt driven we know the state */
225 if (!state->autodetect || state->irq > 0)
Richard Röjforsc277b602009-09-22 06:06:34 -0300226 *std = state->curr_norm;
227 else
228 err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
229
Richard Röjfors42752f72009-09-22 06:07:06 -0300230 mutex_unlock(&state->mutex);
Richard Röjforsc277b602009-09-22 06:06:34 -0300231 return err;
Richard Röjforsd3124292009-09-22 06:05:42 -0300232}
Richard Röjfors6789cb52009-09-18 21:17:20 -0300233
Federico Vagabca7ad12012-04-12 12:39:36 -0300234static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
235 u32 output, u32 config)
236{
237 struct adv7180_state *state = to_state(sd);
238 int ret = mutex_lock_interruptible(&state->mutex);
239 struct i2c_client *client = v4l2_get_subdevdata(sd);
240
241 if (ret)
242 return ret;
243
Federico Vagac9fbedd2012-07-11 11:29:33 -0300244 /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
Federico Vagabca7ad12012-04-12 12:39:36 -0300245 * all inputs and let the card driver take care of validation
246 */
247 if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
248 goto out;
249
250 ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG);
251
252 if (ret < 0)
253 goto out;
254
255 ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
256 ret = i2c_smbus_write_byte_data(client,
257 ADV7180_INPUT_CONTROL_REG, ret | input);
258 state->input = input;
259out:
260 mutex_unlock(&state->mutex);
261 return ret;
262}
263
Richard Röjforsd3124292009-09-22 06:05:42 -0300264static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
265{
Richard Röjfors42752f72009-09-22 06:07:06 -0300266 struct adv7180_state *state = to_state(sd);
267 int ret = mutex_lock_interruptible(&state->mutex);
268 if (ret)
269 return ret;
270
271 ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
272 mutex_unlock(&state->mutex);
273 return ret;
Richard Röjfors6789cb52009-09-18 21:17:20 -0300274}
275
Richard Röjforsc277b602009-09-22 06:06:34 -0300276static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
277{
278 struct adv7180_state *state = to_state(sd);
279 struct i2c_client *client = v4l2_get_subdevdata(sd);
Richard Röjfors42752f72009-09-22 06:07:06 -0300280 int ret = mutex_lock_interruptible(&state->mutex);
281 if (ret)
282 return ret;
Richard Röjforsc277b602009-09-22 06:06:34 -0300283
284 /* all standards -> autodetect */
285 if (std == V4L2_STD_ALL) {
Federico Vagabca7ad12012-04-12 12:39:36 -0300286 ret =
287 i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
288 ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
289 | state->input);
Richard Röjforsc277b602009-09-22 06:06:34 -0300290 if (ret < 0)
291 goto out;
292
Richard Röjfors42752f72009-09-22 06:07:06 -0300293 __adv7180_status(client, NULL, &state->curr_norm);
Richard Röjforsc277b602009-09-22 06:06:34 -0300294 state->autodetect = true;
295 } else {
296 ret = v4l2_std_to_adv7180(std);
297 if (ret < 0)
298 goto out;
299
300 ret = i2c_smbus_write_byte_data(client,
Federico Vagabca7ad12012-04-12 12:39:36 -0300301 ADV7180_INPUT_CONTROL_REG,
302 ret | state->input);
Richard Röjforsc277b602009-09-22 06:06:34 -0300303 if (ret < 0)
304 goto out;
305
306 state->curr_norm = std;
307 state->autodetect = false;
308 }
309 ret = 0;
310out:
Richard Röjfors42752f72009-09-22 06:07:06 -0300311 mutex_unlock(&state->mutex);
Richard Röjforsc277b602009-09-22 06:06:34 -0300312 return ret;
313}
314
Lars-Peter Clausene246c332014-03-10 14:05:39 -0300315static int adv7180_set_power(struct adv7180_state *state,
316 struct i2c_client *client, bool on)
317{
318 u8 val;
319
320 if (on)
321 val = ADV7180_PWR_MAN_ON;
322 else
323 val = ADV7180_PWR_MAN_OFF;
324
325 return i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, val);
326}
327
328static int adv7180_s_power(struct v4l2_subdev *sd, int on)
329{
330 struct adv7180_state *state = to_state(sd);
331 struct i2c_client *client = v4l2_get_subdevdata(sd);
332 int ret;
333
334 ret = mutex_lock_interruptible(&state->mutex);
335 if (ret)
336 return ret;
337
338 ret = adv7180_set_power(state, client, on);
339 if (ret == 0)
340 state->powered = on;
341
342 mutex_unlock(&state->mutex);
343 return ret;
344}
345
Federico Vagac9fbedd2012-07-11 11:29:33 -0300346static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
Federico Vagabca7ad12012-04-12 12:39:36 -0300347{
Federico Vagac9fbedd2012-07-11 11:29:33 -0300348 struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
Federico Vagabca7ad12012-04-12 12:39:36 -0300349 struct adv7180_state *state = to_state(sd);
350 struct i2c_client *client = v4l2_get_subdevdata(sd);
351 int ret = mutex_lock_interruptible(&state->mutex);
Federico Vagac9fbedd2012-07-11 11:29:33 -0300352 int val;
353
Federico Vagabca7ad12012-04-12 12:39:36 -0300354 if (ret)
355 return ret;
Federico Vagac9fbedd2012-07-11 11:29:33 -0300356 val = ctrl->val;
Federico Vagabca7ad12012-04-12 12:39:36 -0300357 switch (ctrl->id) {
358 case V4L2_CID_BRIGHTNESS:
Federico Vagac9fbedd2012-07-11 11:29:33 -0300359 ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, val);
Federico Vagabca7ad12012-04-12 12:39:36 -0300360 break;
361 case V4L2_CID_HUE:
Federico Vagabca7ad12012-04-12 12:39:36 -0300362 /*Hue is inverted according to HSL chart */
Federico Vagac9fbedd2012-07-11 11:29:33 -0300363 ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, -val);
Federico Vagabca7ad12012-04-12 12:39:36 -0300364 break;
365 case V4L2_CID_CONTRAST:
Federico Vagac9fbedd2012-07-11 11:29:33 -0300366 ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, val);
Federico Vagabca7ad12012-04-12 12:39:36 -0300367 break;
368 case V4L2_CID_SATURATION:
Federico Vagabca7ad12012-04-12 12:39:36 -0300369 /*
370 *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
371 *Let's not confuse the user, everybody understands saturation
372 */
Federico Vagac9fbedd2012-07-11 11:29:33 -0300373 ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG,
374 val);
Federico Vagabca7ad12012-04-12 12:39:36 -0300375 if (ret < 0)
376 break;
Federico Vagac9fbedd2012-07-11 11:29:33 -0300377 ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG,
378 val);
Federico Vagabca7ad12012-04-12 12:39:36 -0300379 break;
380 default:
381 ret = -EINVAL;
382 }
383
384 mutex_unlock(&state->mutex);
385 return ret;
386}
387
Federico Vagac9fbedd2012-07-11 11:29:33 -0300388static const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
389 .s_ctrl = adv7180_s_ctrl,
390};
391
392static int adv7180_init_controls(struct adv7180_state *state)
393{
394 v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
395
396 v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
397 V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN,
398 ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF);
399 v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
400 V4L2_CID_CONTRAST, ADV7180_CON_MIN,
401 ADV7180_CON_MAX, 1, ADV7180_CON_DEF);
402 v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
403 V4L2_CID_SATURATION, ADV7180_SAT_MIN,
404 ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF);
405 v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
406 V4L2_CID_HUE, ADV7180_HUE_MIN,
407 ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
408 state->sd.ctrl_handler = &state->ctrl_hdl;
409 if (state->ctrl_hdl.error) {
410 int err = state->ctrl_hdl.error;
411
412 v4l2_ctrl_handler_free(&state->ctrl_hdl);
413 return err;
414 }
415 v4l2_ctrl_handler_setup(&state->ctrl_hdl);
416
417 return 0;
418}
419static void adv7180_exit_controls(struct adv7180_state *state)
420{
421 v4l2_ctrl_handler_free(&state->ctrl_hdl);
422}
423
Vladimir Barinovcccb83f2013-05-29 14:50:57 -0300424static int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
425 enum v4l2_mbus_pixelcode *code)
426{
427 if (index > 0)
428 return -EINVAL;
429
430 *code = V4L2_MBUS_FMT_YUYV8_2X8;
431
432 return 0;
433}
434
435static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
436 struct v4l2_mbus_framefmt *fmt)
437{
438 struct adv7180_state *state = to_state(sd);
439
440 fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
441 fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
442 fmt->field = V4L2_FIELD_INTERLACED;
443 fmt->width = 720;
444 fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
445
446 return 0;
447}
448
449static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
450 struct v4l2_mbus_config *cfg)
451{
452 /*
453 * The ADV7180 sensor supports BT.601/656 output modes.
454 * The BT.656 is default and not yet configurable by s/w.
455 */
456 cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
457 V4L2_MBUS_DATA_ACTIVE_HIGH;
458 cfg->type = V4L2_MBUS_BT656;
459
460 return 0;
461}
462
Richard Röjfors6789cb52009-09-18 21:17:20 -0300463static const struct v4l2_subdev_video_ops adv7180_video_ops = {
Laurent Pinchart8774bed2014-04-28 16:53:01 -0300464 .s_std = adv7180_s_std,
Richard Röjfors6789cb52009-09-18 21:17:20 -0300465 .querystd = adv7180_querystd,
Richard Röjforsd3124292009-09-22 06:05:42 -0300466 .g_input_status = adv7180_g_input_status,
Federico Vagabca7ad12012-04-12 12:39:36 -0300467 .s_routing = adv7180_s_routing,
Vladimir Barinovcccb83f2013-05-29 14:50:57 -0300468 .enum_mbus_fmt = adv7180_enum_mbus_fmt,
469 .try_mbus_fmt = adv7180_mbus_fmt,
470 .g_mbus_fmt = adv7180_mbus_fmt,
471 .s_mbus_fmt = adv7180_mbus_fmt,
472 .g_mbus_config = adv7180_g_mbus_config,
Richard Röjfors6789cb52009-09-18 21:17:20 -0300473};
474
475static const struct v4l2_subdev_core_ops adv7180_core_ops = {
Lars-Peter Clausene246c332014-03-10 14:05:39 -0300476 .s_power = adv7180_s_power,
Richard Röjfors6789cb52009-09-18 21:17:20 -0300477};
478
479static const struct v4l2_subdev_ops adv7180_ops = {
480 .core = &adv7180_core_ops,
481 .video = &adv7180_video_ops,
482};
483
Lars-Peter Clausen0c255342014-03-07 13:14:31 -0300484static irqreturn_t adv7180_irq(int irq, void *devid)
Richard Röjfors42752f72009-09-22 06:07:06 -0300485{
Lars-Peter Clausen0c255342014-03-07 13:14:31 -0300486 struct adv7180_state *state = devid;
Richard Röjfors42752f72009-09-22 06:07:06 -0300487 struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
488 u8 isr3;
489
490 mutex_lock(&state->mutex);
491 i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
Federico Vagabca7ad12012-04-12 12:39:36 -0300492 ADV7180_ADI_CTRL_IRQ_SPACE);
Richard Röjfors42752f72009-09-22 06:07:06 -0300493 isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
494 /* clear */
495 i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
496 i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
497
498 if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
499 __adv7180_status(client, NULL, &state->curr_norm);
500 mutex_unlock(&state->mutex);
501
Richard Röjfors42752f72009-09-22 06:07:06 -0300502 return IRQ_HANDLED;
503}
504
Federico Vagabca7ad12012-04-12 12:39:36 -0300505static int init_device(struct i2c_client *client, struct adv7180_state *state)
506{
507 int ret;
508
509 /* Initialize adv7180 */
510 /* Enable autodetection */
511 if (state->autodetect) {
512 ret =
513 i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
514 ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
515 | state->input);
516 if (ret < 0)
517 return ret;
518
519 ret =
520 i2c_smbus_write_byte_data(client,
521 ADV7180_AUTODETECT_ENABLE_REG,
522 ADV7180_AUTODETECT_DEFAULT);
523 if (ret < 0)
524 return ret;
525 } else {
526 ret = v4l2_std_to_adv7180(state->curr_norm);
527 if (ret < 0)
528 return ret;
529
530 ret =
531 i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
532 ret | state->input);
533 if (ret < 0)
534 return ret;
535
536 }
537 /* ITU-R BT.656-4 compatible */
538 ret = i2c_smbus_write_byte_data(client,
539 ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
540 ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
541 if (ret < 0)
542 return ret;
543
544 /* Manually set V bit end position in NTSC mode */
545 ret = i2c_smbus_write_byte_data(client,
546 ADV7180_NTSC_V_BIT_END_REG,
547 ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
548 if (ret < 0)
549 return ret;
550
551 /* read current norm */
552 __adv7180_status(client, NULL, &state->curr_norm);
553
554 /* register for interrupts */
555 if (state->irq > 0) {
Lars-Peter Clausen0c255342014-03-07 13:14:31 -0300556 ret = request_threaded_irq(state->irq, NULL, adv7180_irq,
557 IRQF_ONESHOT, KBUILD_MODNAME, state);
Federico Vagabca7ad12012-04-12 12:39:36 -0300558 if (ret)
559 return ret;
560
561 ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
562 ADV7180_ADI_CTRL_IRQ_SPACE);
563 if (ret < 0)
Alexey Khoroshilovdf065b32014-03-14 18:04:03 -0300564 goto err;
Federico Vagabca7ad12012-04-12 12:39:36 -0300565
566 /* config the Interrupt pin to be active low */
567 ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
568 ADV7180_ICONF1_ACTIVE_LOW |
569 ADV7180_ICONF1_PSYNC_ONLY);
570 if (ret < 0)
Alexey Khoroshilovdf065b32014-03-14 18:04:03 -0300571 goto err;
Federico Vagabca7ad12012-04-12 12:39:36 -0300572
573 ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
574 if (ret < 0)
Alexey Khoroshilovdf065b32014-03-14 18:04:03 -0300575 goto err;
Federico Vagabca7ad12012-04-12 12:39:36 -0300576
577 ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
578 if (ret < 0)
Alexey Khoroshilovdf065b32014-03-14 18:04:03 -0300579 goto err;
Federico Vagabca7ad12012-04-12 12:39:36 -0300580
581 /* enable AD change interrupts interrupts */
582 ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
583 ADV7180_IRQ3_AD_CHANGE);
584 if (ret < 0)
Alexey Khoroshilovdf065b32014-03-14 18:04:03 -0300585 goto err;
Federico Vagabca7ad12012-04-12 12:39:36 -0300586
587 ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
588 if (ret < 0)
Alexey Khoroshilovdf065b32014-03-14 18:04:03 -0300589 goto err;
Federico Vagabca7ad12012-04-12 12:39:36 -0300590
591 ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
592 0);
593 if (ret < 0)
Alexey Khoroshilovdf065b32014-03-14 18:04:03 -0300594 goto err;
Federico Vagabca7ad12012-04-12 12:39:36 -0300595 }
596
Federico Vagabca7ad12012-04-12 12:39:36 -0300597 return 0;
Alexey Khoroshilovdf065b32014-03-14 18:04:03 -0300598
599err:
600 free_irq(state->irq, state);
601 return ret;
Federico Vagabca7ad12012-04-12 12:39:36 -0300602}
Richard Röjfors6789cb52009-09-18 21:17:20 -0300603
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -0800604static int adv7180_probe(struct i2c_client *client,
605 const struct i2c_device_id *id)
Richard Röjfors6789cb52009-09-18 21:17:20 -0300606{
607 struct adv7180_state *state;
608 struct v4l2_subdev *sd;
609 int ret;
610
611 /* Check if the adapter supports the needed features */
612 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
613 return -EIO;
614
615 v4l_info(client, "chip found @ 0x%02x (%s)\n",
Federico Vagabca7ad12012-04-12 12:39:36 -0300616 client->addr, client->adapter->name);
Richard Röjfors6789cb52009-09-18 21:17:20 -0300617
Laurent Pinchartc02b2112013-05-02 08:29:43 -0300618 state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
Richard Röjfors42752f72009-09-22 06:07:06 -0300619 if (state == NULL) {
620 ret = -ENOMEM;
621 goto err;
622 }
623
624 state->irq = client->irq;
Richard Röjfors42752f72009-09-22 06:07:06 -0300625 mutex_init(&state->mutex);
Richard Röjforsc277b602009-09-22 06:06:34 -0300626 state->autodetect = true;
Lars-Peter Clausene246c332014-03-10 14:05:39 -0300627 state->powered = true;
Federico Vagabca7ad12012-04-12 12:39:36 -0300628 state->input = 0;
Richard Röjfors6789cb52009-09-18 21:17:20 -0300629 sd = &state->sd;
630 v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
631
Federico Vagac9fbedd2012-07-11 11:29:33 -0300632 ret = adv7180_init_controls(state);
633 if (ret)
Richard Röjfors42752f72009-09-22 06:07:06 -0300634 goto err_unreg_subdev;
Federico Vagac9fbedd2012-07-11 11:29:33 -0300635 ret = init_device(client, state);
636 if (ret)
637 goto err_free_ctrl;
Lars-Peter Clausenfa5b7942014-03-07 13:14:32 -0300638
639 ret = v4l2_async_register_subdev(sd);
640 if (ret)
641 goto err_free_irq;
642
Richard Röjfors6789cb52009-09-18 21:17:20 -0300643 return 0;
Richard Röjfors42752f72009-09-22 06:07:06 -0300644
Lars-Peter Clausenfa5b7942014-03-07 13:14:32 -0300645err_free_irq:
646 if (state->irq > 0)
647 free_irq(client->irq, state);
Federico Vagac9fbedd2012-07-11 11:29:33 -0300648err_free_ctrl:
649 adv7180_exit_controls(state);
Richard Röjfors42752f72009-09-22 06:07:06 -0300650err_unreg_subdev:
Lars-Peter Clausen297a0ae2014-03-07 13:14:27 -0300651 mutex_destroy(&state->mutex);
Richard Röjfors42752f72009-09-22 06:07:06 -0300652err:
Richard Röjfors42752f72009-09-22 06:07:06 -0300653 return ret;
Richard Röjfors6789cb52009-09-18 21:17:20 -0300654}
655
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -0800656static int adv7180_remove(struct i2c_client *client)
Richard Röjfors6789cb52009-09-18 21:17:20 -0300657{
658 struct v4l2_subdev *sd = i2c_get_clientdata(client);
Richard Röjfors42752f72009-09-22 06:07:06 -0300659 struct adv7180_state *state = to_state(sd);
Richard Röjfors6789cb52009-09-18 21:17:20 -0300660
Lars-Peter Clausenfa5b7942014-03-07 13:14:32 -0300661 v4l2_async_unregister_subdev(sd);
662
Lars-Peter Clausen0c255342014-03-07 13:14:31 -0300663 if (state->irq > 0)
Richard Röjfors42752f72009-09-22 06:07:06 -0300664 free_irq(client->irq, state);
Richard Röjfors42752f72009-09-22 06:07:06 -0300665
Richard Röjfors6789cb52009-09-18 21:17:20 -0300666 v4l2_device_unregister_subdev(sd);
Lars-Peter Clausenb13f4af2014-03-07 13:14:28 -0300667 adv7180_exit_controls(state);
Lars-Peter Clausen297a0ae2014-03-07 13:14:27 -0300668 mutex_destroy(&state->mutex);
Richard Röjfors6789cb52009-09-18 21:17:20 -0300669 return 0;
670}
671
672static const struct i2c_device_id adv7180_id[] = {
Federico Vagac9fbedd2012-07-11 11:29:33 -0300673 {KBUILD_MODNAME, 0},
Richard Röjfors6789cb52009-09-18 21:17:20 -0300674 {},
675};
676
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300677#ifdef CONFIG_PM_SLEEP
678static int adv7180_suspend(struct device *dev)
Federico Vagabca7ad12012-04-12 12:39:36 -0300679{
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300680 struct i2c_client *client = to_i2c_client(dev);
Lars-Peter Clausene246c332014-03-10 14:05:39 -0300681 struct v4l2_subdev *sd = i2c_get_clientdata(client);
682 struct adv7180_state *state = to_state(sd);
Federico Vagabca7ad12012-04-12 12:39:36 -0300683
Lars-Peter Clausene246c332014-03-10 14:05:39 -0300684 return adv7180_set_power(state, client, false);
Federico Vagabca7ad12012-04-12 12:39:36 -0300685}
686
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300687static int adv7180_resume(struct device *dev)
Federico Vagabca7ad12012-04-12 12:39:36 -0300688{
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300689 struct i2c_client *client = to_i2c_client(dev);
Federico Vagabca7ad12012-04-12 12:39:36 -0300690 struct v4l2_subdev *sd = i2c_get_clientdata(client);
691 struct adv7180_state *state = to_state(sd);
692 int ret;
693
Lars-Peter Clausene246c332014-03-10 14:05:39 -0300694 if (state->powered) {
695 ret = adv7180_set_power(state, client, true);
696 if (ret)
697 return ret;
698 }
Federico Vagabca7ad12012-04-12 12:39:36 -0300699 ret = init_device(client, state);
700 if (ret < 0)
701 return ret;
702 return 0;
703}
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300704
705static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
706#define ADV7180_PM_OPS (&adv7180_pm_ops)
707
708#else
709#define ADV7180_PM_OPS NULL
Federico Vagabca7ad12012-04-12 12:39:36 -0300710#endif
711
Richard Röjfors6789cb52009-09-18 21:17:20 -0300712MODULE_DEVICE_TABLE(i2c, adv7180_id);
713
714static struct i2c_driver adv7180_driver = {
715 .driver = {
Federico Vagabca7ad12012-04-12 12:39:36 -0300716 .owner = THIS_MODULE,
Federico Vagac9fbedd2012-07-11 11:29:33 -0300717 .name = KBUILD_MODNAME,
Lars-Peter Clausencc1088d2013-04-13 05:25:59 -0300718 .pm = ADV7180_PM_OPS,
Federico Vagabca7ad12012-04-12 12:39:36 -0300719 },
720 .probe = adv7180_probe,
Greg Kroah-Hartman4c62e972012-12-21 13:17:53 -0800721 .remove = adv7180_remove,
Federico Vagabca7ad12012-04-12 12:39:36 -0300722 .id_table = adv7180_id,
Richard Röjfors6789cb52009-09-18 21:17:20 -0300723};
724
Axel Linc6e8d862012-02-12 06:56:32 -0300725module_i2c_driver(adv7180_driver);
Richard Röjfors6789cb52009-09-18 21:17:20 -0300726
727MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
728MODULE_AUTHOR("Mocean Laboratories");
729MODULE_LICENSE("GPL v2");