• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/media/video/
1/*
2 * adv7180.c Analog Devices ADV7180 video decoder driver
3 * Copyright (c) 2009 Intel Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/errno.h>
22#include <linux/kernel.h>
23#include <linux/interrupt.h>
24#include <linux/i2c.h>
25#include <linux/i2c-id.h>
26#include <linux/slab.h>
27#include <media/v4l2-ioctl.h>
28#include <linux/videodev2.h>
29#include <media/v4l2-device.h>
30#include <media/v4l2-chip-ident.h>
31#include <linux/mutex.h>
32
33#define DRIVER_NAME "adv7180"
34
35#define ADV7180_INPUT_CONTROL_REG			0x00
36#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM	0x00
37#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
38#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM	0x20
39#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM	0x30
40#define ADV7180_INPUT_CONTROL_NTSC_J			0x40
41#define ADV7180_INPUT_CONTROL_NTSC_M			0x50
42#define ADV7180_INPUT_CONTROL_PAL60			0x60
43#define ADV7180_INPUT_CONTROL_NTSC_443			0x70
44#define ADV7180_INPUT_CONTROL_PAL_BG			0x80
45#define ADV7180_INPUT_CONTROL_PAL_N			0x90
46#define ADV7180_INPUT_CONTROL_PAL_M			0xa0
47#define ADV7180_INPUT_CONTROL_PAL_M_PED			0xb0
48#define ADV7180_INPUT_CONTROL_PAL_COMB_N		0xc0
49#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED		0xd0
50#define ADV7180_INPUT_CONTROL_PAL_SECAM			0xe0
51#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED		0xf0
52
53#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG		0x04
54#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS		0xC5
55
56#define ADV7180_AUTODETECT_ENABLE_REG			0x07
57#define ADV7180_AUTODETECT_DEFAULT			0x7f
58
59#define ADV7180_ADI_CTRL_REG				0x0e
60#define ADV7180_ADI_CTRL_IRQ_SPACE			0x20
61
62#define ADV7180_STATUS1_REG				0x10
63#define ADV7180_STATUS1_IN_LOCK		0x01
64#define ADV7180_STATUS1_AUTOD_MASK	0x70
65#define ADV7180_STATUS1_AUTOD_NTSM_M_J	0x00
66#define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10
67#define ADV7180_STATUS1_AUTOD_PAL_M	0x20
68#define ADV7180_STATUS1_AUTOD_PAL_60	0x30
69#define ADV7180_STATUS1_AUTOD_PAL_B_G	0x40
70#define ADV7180_STATUS1_AUTOD_SECAM	0x50
71#define ADV7180_STATUS1_AUTOD_PAL_COMB	0x60
72#define ADV7180_STATUS1_AUTOD_SECAM_525	0x70
73
74#define ADV7180_IDENT_REG 0x11
75#define ADV7180_ID_7180 0x18
76
77#define ADV7180_ICONF1_ADI		0x40
78#define ADV7180_ICONF1_ACTIVE_LOW	0x01
79#define ADV7180_ICONF1_PSYNC_ONLY	0x10
80#define ADV7180_ICONF1_ACTIVE_TO_CLR	0xC0
81
82#define ADV7180_IRQ1_LOCK	0x01
83#define ADV7180_IRQ1_UNLOCK	0x02
84#define ADV7180_ISR1_ADI	0x42
85#define ADV7180_ICR1_ADI	0x43
86#define ADV7180_IMR1_ADI	0x44
87#define ADV7180_IMR2_ADI	0x48
88#define ADV7180_IRQ3_AD_CHANGE	0x08
89#define ADV7180_ISR3_ADI	0x4A
90#define ADV7180_ICR3_ADI	0x4B
91#define ADV7180_IMR3_ADI	0x4C
92#define ADV7180_IMR4_ADI	0x50
93
94struct adv7180_state {
95	struct v4l2_subdev	sd;
96	struct work_struct	work;
97	struct mutex		mutex; /* mutual excl. when accessing chip */
98	int			irq;
99	v4l2_std_id		curr_norm;
100	bool			autodetect;
101};
102
103static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
104{
105	switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
106	case ADV7180_STATUS1_AUTOD_NTSM_M_J:
107		return V4L2_STD_NTSC;
108	case ADV7180_STATUS1_AUTOD_NTSC_4_43:
109		return V4L2_STD_NTSC_443;
110	case ADV7180_STATUS1_AUTOD_PAL_M:
111		return V4L2_STD_PAL_M;
112	case ADV7180_STATUS1_AUTOD_PAL_60:
113		return V4L2_STD_PAL_60;
114	case ADV7180_STATUS1_AUTOD_PAL_B_G:
115		return V4L2_STD_PAL;
116	case ADV7180_STATUS1_AUTOD_SECAM:
117		return V4L2_STD_SECAM;
118	case ADV7180_STATUS1_AUTOD_PAL_COMB:
119		return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
120	case ADV7180_STATUS1_AUTOD_SECAM_525:
121		return V4L2_STD_SECAM;
122	default:
123		return V4L2_STD_UNKNOWN;
124	}
125}
126
127static int v4l2_std_to_adv7180(v4l2_std_id std)
128{
129	if (std == V4L2_STD_PAL_60)
130		return ADV7180_INPUT_CONTROL_PAL60;
131	if (std == V4L2_STD_NTSC_443)
132		return ADV7180_INPUT_CONTROL_NTSC_443;
133	if (std == V4L2_STD_PAL_N)
134		return ADV7180_INPUT_CONTROL_PAL_N;
135	if (std == V4L2_STD_PAL_M)
136		return ADV7180_INPUT_CONTROL_PAL_M;
137	if (std == V4L2_STD_PAL_Nc)
138		return ADV7180_INPUT_CONTROL_PAL_COMB_N;
139
140	if (std & V4L2_STD_PAL)
141		return ADV7180_INPUT_CONTROL_PAL_BG;
142	if (std & V4L2_STD_NTSC)
143		return ADV7180_INPUT_CONTROL_NTSC_M;
144	if (std & V4L2_STD_SECAM)
145		return ADV7180_INPUT_CONTROL_PAL_SECAM;
146
147	return -EINVAL;
148}
149
150static u32 adv7180_status_to_v4l2(u8 status1)
151{
152	if (!(status1 & ADV7180_STATUS1_IN_LOCK))
153		return V4L2_IN_ST_NO_SIGNAL;
154
155	return 0;
156}
157
158static int __adv7180_status(struct i2c_client *client, u32 *status,
159	v4l2_std_id *std)
160{
161	int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
162
163	if (status1 < 0)
164		return status1;
165
166	if (status)
167		*status = adv7180_status_to_v4l2(status1);
168	if (std)
169		*std = adv7180_std_to_v4l2(status1);
170
171	return 0;
172}
173
174static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
175{
176	return container_of(sd, struct adv7180_state, sd);
177}
178
179static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
180{
181	struct adv7180_state *state = to_state(sd);
182	int err = mutex_lock_interruptible(&state->mutex);
183	if (err)
184		return err;
185
186	/* when we are interrupt driven we know the state */
187	if (!state->autodetect || state->irq > 0)
188		*std = state->curr_norm;
189	else
190		err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
191
192	mutex_unlock(&state->mutex);
193	return err;
194}
195
196static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
197{
198	struct adv7180_state *state = to_state(sd);
199	int ret = mutex_lock_interruptible(&state->mutex);
200	if (ret)
201		return ret;
202
203	ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
204	mutex_unlock(&state->mutex);
205	return ret;
206}
207
208static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
209	struct v4l2_dbg_chip_ident *chip)
210{
211	struct i2c_client *client = v4l2_get_subdevdata(sd);
212
213	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7180, 0);
214}
215
216static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
217{
218	struct adv7180_state *state = to_state(sd);
219	struct i2c_client *client = v4l2_get_subdevdata(sd);
220	int ret = mutex_lock_interruptible(&state->mutex);
221	if (ret)
222		return ret;
223
224	/* all standards -> autodetect */
225	if (std == V4L2_STD_ALL) {
226		ret = i2c_smbus_write_byte_data(client,
227			ADV7180_INPUT_CONTROL_REG,
228			ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
229		if (ret < 0)
230			goto out;
231
232		__adv7180_status(client, NULL, &state->curr_norm);
233		state->autodetect = true;
234	} else {
235		ret = v4l2_std_to_adv7180(std);
236		if (ret < 0)
237			goto out;
238
239		ret = i2c_smbus_write_byte_data(client,
240			ADV7180_INPUT_CONTROL_REG, ret);
241		if (ret < 0)
242			goto out;
243
244		state->curr_norm = std;
245		state->autodetect = false;
246	}
247	ret = 0;
248out:
249	mutex_unlock(&state->mutex);
250	return ret;
251}
252
253static const struct v4l2_subdev_video_ops adv7180_video_ops = {
254	.querystd = adv7180_querystd,
255	.g_input_status = adv7180_g_input_status,
256};
257
258static const struct v4l2_subdev_core_ops adv7180_core_ops = {
259	.g_chip_ident = adv7180_g_chip_ident,
260	.s_std = adv7180_s_std,
261};
262
263static const struct v4l2_subdev_ops adv7180_ops = {
264	.core = &adv7180_core_ops,
265	.video = &adv7180_video_ops,
266};
267
268static void adv7180_work(struct work_struct *work)
269{
270	struct adv7180_state *state = container_of(work, struct adv7180_state,
271		work);
272	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
273	u8 isr3;
274
275	mutex_lock(&state->mutex);
276	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
277		ADV7180_ADI_CTRL_IRQ_SPACE);
278	isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
279	/* clear */
280	i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
281	i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
282
283	if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
284		__adv7180_status(client, NULL, &state->curr_norm);
285	mutex_unlock(&state->mutex);
286
287	enable_irq(state->irq);
288}
289
290static irqreturn_t adv7180_irq(int irq, void *devid)
291{
292	struct adv7180_state *state = devid;
293
294	schedule_work(&state->work);
295
296	disable_irq_nosync(state->irq);
297
298	return IRQ_HANDLED;
299}
300
301/*
302 * Generic i2c probe
303 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
304 */
305
306static __devinit int adv7180_probe(struct i2c_client *client,
307			const struct i2c_device_id *id)
308{
309	struct adv7180_state *state;
310	struct v4l2_subdev *sd;
311	int ret;
312
313	/* Check if the adapter supports the needed features */
314	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
315		return -EIO;
316
317	v4l_info(client, "chip found @ 0x%02x (%s)\n",
318			client->addr << 1, client->adapter->name);
319
320	state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
321	if (state == NULL) {
322		ret = -ENOMEM;
323		goto err;
324	}
325
326	state->irq = client->irq;
327	INIT_WORK(&state->work, adv7180_work);
328	mutex_init(&state->mutex);
329	state->autodetect = true;
330	sd = &state->sd;
331	v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
332
333	/* Initialize adv7180 */
334	/* Enable autodetection */
335	ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
336		ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
337	if (ret < 0)
338		goto err_unreg_subdev;
339
340	ret = i2c_smbus_write_byte_data(client, ADV7180_AUTODETECT_ENABLE_REG,
341		ADV7180_AUTODETECT_DEFAULT);
342	if (ret < 0)
343		goto err_unreg_subdev;
344
345	/* ITU-R BT.656-4 compatible */
346	ret = i2c_smbus_write_byte_data(client,
347		ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
348		ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
349	if (ret < 0)
350		goto err_unreg_subdev;
351
352	/* read current norm */
353	__adv7180_status(client, NULL, &state->curr_norm);
354
355	/* register for interrupts */
356	if (state->irq > 0) {
357		ret = request_irq(state->irq, adv7180_irq, 0, DRIVER_NAME,
358			state);
359		if (ret)
360			goto err_unreg_subdev;
361
362		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
363			ADV7180_ADI_CTRL_IRQ_SPACE);
364		if (ret < 0)
365			goto err_unreg_subdev;
366
367		/* config the Interrupt pin to be active low */
368		ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
369			ADV7180_ICONF1_ACTIVE_LOW | ADV7180_ICONF1_PSYNC_ONLY);
370		if (ret < 0)
371			goto err_unreg_subdev;
372
373		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
374		if (ret < 0)
375			goto err_unreg_subdev;
376
377		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
378		if (ret < 0)
379			goto err_unreg_subdev;
380
381		/* enable AD change interrupts interrupts */
382		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
383			ADV7180_IRQ3_AD_CHANGE);
384		if (ret < 0)
385			goto err_unreg_subdev;
386
387		ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
388		if (ret < 0)
389			goto err_unreg_subdev;
390
391		ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
392			0);
393		if (ret < 0)
394			goto err_unreg_subdev;
395	}
396
397	return 0;
398
399err_unreg_subdev:
400	mutex_destroy(&state->mutex);
401	v4l2_device_unregister_subdev(sd);
402	kfree(state);
403err:
404	printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", ret);
405	return ret;
406}
407
408static __devexit int adv7180_remove(struct i2c_client *client)
409{
410	struct v4l2_subdev *sd = i2c_get_clientdata(client);
411	struct adv7180_state *state = to_state(sd);
412
413	if (state->irq > 0) {
414		free_irq(client->irq, state);
415		if (cancel_work_sync(&state->work)) {
416			/*
417			 * Work was pending, therefore we need to enable
418			 * IRQ here to balance the disable_irq() done in the
419			 * interrupt handler.
420			 */
421			enable_irq(state->irq);
422		}
423	}
424
425	mutex_destroy(&state->mutex);
426	v4l2_device_unregister_subdev(sd);
427	kfree(to_state(sd));
428	return 0;
429}
430
431static const struct i2c_device_id adv7180_id[] = {
432	{DRIVER_NAME, 0},
433	{},
434};
435
436MODULE_DEVICE_TABLE(i2c, adv7180_id);
437
438static struct i2c_driver adv7180_driver = {
439	.driver = {
440		.owner	= THIS_MODULE,
441		.name	= DRIVER_NAME,
442	},
443	.probe		= adv7180_probe,
444	.remove		= __devexit_p(adv7180_remove),
445	.id_table	= adv7180_id,
446};
447
448static __init int adv7180_init(void)
449{
450	return i2c_add_driver(&adv7180_driver);
451}
452
453static __exit void adv7180_exit(void)
454{
455	i2c_del_driver(&adv7180_driver);
456}
457
458module_init(adv7180_init);
459module_exit(adv7180_exit);
460
461MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
462MODULE_AUTHOR("Mocean Laboratories");
463MODULE_LICENSE("GPL v2");
464