xref: /linux/drivers/media/i2c/cx25840/cx25840-core.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2cb7a01acSMauro Carvalho Chehab /* cx25840 - Conexant CX25840 audio/video decoder driver
3cb7a01acSMauro Carvalho Chehab  *
4cb7a01acSMauro Carvalho Chehab  * Copyright (C) 2004 Ulf Eklund
5cb7a01acSMauro Carvalho Chehab  *
6cb7a01acSMauro Carvalho Chehab  * Based on the saa7115 driver and on the first version of Chris Kennedy's
7cb7a01acSMauro Carvalho Chehab  * cx25840 driver.
8cb7a01acSMauro Carvalho Chehab  *
9cb7a01acSMauro Carvalho Chehab  * Changes by Tyler Trafford <tatrafford@comcast.net>
10cb7a01acSMauro Carvalho Chehab  *    - cleanup/rewrite for V4L2 API (2005)
11cb7a01acSMauro Carvalho Chehab  *
12cb7a01acSMauro Carvalho Chehab  * VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
13cb7a01acSMauro Carvalho Chehab  *
14cb7a01acSMauro Carvalho Chehab  * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
15cb7a01acSMauro Carvalho Chehab  * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
16cb7a01acSMauro Carvalho Chehab  *
17cb7a01acSMauro Carvalho Chehab  * CX23885 support by Steven Toth <stoth@linuxtv.org>.
18cb7a01acSMauro Carvalho Chehab  *
19cb7a01acSMauro Carvalho Chehab  * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are
20cb7a01acSMauro Carvalho Chehab  * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
21cb7a01acSMauro Carvalho Chehab  *
22cb7a01acSMauro Carvalho Chehab  * CX23888 DIF support for the HVR1850
23cb7a01acSMauro Carvalho Chehab  * Copyright (C) 2011 Steven Toth <stoth@kernellabs.com>
24cb7a01acSMauro Carvalho Chehab  *
25e81a9076SMaciej S. Szmigiero  * CX2584x pin to pad mapping and output format configuration support are
26e81a9076SMaciej S. Szmigiero  * Copyright (C) 2011 Maciej S. Szmigiero <mail@maciej.szmigiero.name>
27cb7a01acSMauro Carvalho Chehab  */
28cb7a01acSMauro Carvalho Chehab 
29cb7a01acSMauro Carvalho Chehab #include <linux/kernel.h>
30cb7a01acSMauro Carvalho Chehab #include <linux/module.h>
31cb7a01acSMauro Carvalho Chehab #include <linux/slab.h>
32cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h>
33cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h>
34cb7a01acSMauro Carvalho Chehab #include <linux/delay.h>
35cb7a01acSMauro Carvalho Chehab #include <linux/math64.h>
36cb7a01acSMauro Carvalho Chehab #include <media/v4l2-common.h>
37d647f0b7SMauro Carvalho Chehab #include <media/drv-intf/cx25840.h>
38cb7a01acSMauro Carvalho Chehab 
39cb7a01acSMauro Carvalho Chehab #include "cx25840-core.h"
40cb7a01acSMauro Carvalho Chehab 
41cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
42cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
43cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL");
44cb7a01acSMauro Carvalho Chehab 
45cb7a01acSMauro Carvalho Chehab #define CX25840_VID_INT_STAT_REG 0x410
46cb7a01acSMauro Carvalho Chehab #define CX25840_VID_INT_STAT_BITS 0x0000ffff
47cb7a01acSMauro Carvalho Chehab #define CX25840_VID_INT_MASK_BITS 0xffff0000
48cb7a01acSMauro Carvalho Chehab #define CX25840_VID_INT_MASK_SHFT 16
49cb7a01acSMauro Carvalho Chehab #define CX25840_VID_INT_MASK_REG 0x412
50cb7a01acSMauro Carvalho Chehab 
51cb7a01acSMauro Carvalho Chehab #define CX23885_AUD_MC_INT_MASK_REG 0x80c
52cb7a01acSMauro Carvalho Chehab #define CX23885_AUD_MC_INT_STAT_BITS 0xffff0000
53cb7a01acSMauro Carvalho Chehab #define CX23885_AUD_MC_INT_CTRL_BITS 0x0000ffff
54cb7a01acSMauro Carvalho Chehab #define CX23885_AUD_MC_INT_STAT_SHFT 16
55cb7a01acSMauro Carvalho Chehab 
56cb7a01acSMauro Carvalho Chehab #define CX25840_AUD_INT_CTRL_REG 0x812
57cb7a01acSMauro Carvalho Chehab #define CX25840_AUD_INT_STAT_REG 0x813
58cb7a01acSMauro Carvalho Chehab 
59cb7a01acSMauro Carvalho Chehab #define CX23885_PIN_CTRL_IRQ_REG 0x123
60cb7a01acSMauro Carvalho Chehab #define CX23885_PIN_CTRL_IRQ_IR_STAT  0x40
61cb7a01acSMauro Carvalho Chehab #define CX23885_PIN_CTRL_IRQ_AUD_STAT 0x20
62cb7a01acSMauro Carvalho Chehab #define CX23885_PIN_CTRL_IRQ_VID_STAT 0x10
63cb7a01acSMauro Carvalho Chehab 
64cb7a01acSMauro Carvalho Chehab #define CX25840_IR_STATS_REG	0x210
65cb7a01acSMauro Carvalho Chehab #define CX25840_IR_IRQEN_REG	0x214
66cb7a01acSMauro Carvalho Chehab 
67cb7a01acSMauro Carvalho Chehab static int cx25840_debug;
68cb7a01acSMauro Carvalho Chehab 
69cb7a01acSMauro Carvalho Chehab module_param_named(debug, cx25840_debug, int, 0644);
70cb7a01acSMauro Carvalho Chehab 
71cb7a01acSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]");
72cb7a01acSMauro Carvalho Chehab 
73cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
74cb7a01acSMauro Carvalho Chehab static void cx23888_std_setup(struct i2c_client *client);
75cb7a01acSMauro Carvalho Chehab 
cx25840_write(struct i2c_client * client,u16 addr,u8 value)76cb7a01acSMauro Carvalho Chehab int cx25840_write(struct i2c_client *client, u16 addr, u8 value)
77cb7a01acSMauro Carvalho Chehab {
78cb7a01acSMauro Carvalho Chehab 	u8 buffer[3];
7910a34367SMauro Carvalho Chehab 
80cb7a01acSMauro Carvalho Chehab 	buffer[0] = addr >> 8;
81cb7a01acSMauro Carvalho Chehab 	buffer[1] = addr & 0xff;
82cb7a01acSMauro Carvalho Chehab 	buffer[2] = value;
83cb7a01acSMauro Carvalho Chehab 	return i2c_master_send(client, buffer, 3);
84cb7a01acSMauro Carvalho Chehab }
85cb7a01acSMauro Carvalho Chehab 
cx25840_write4(struct i2c_client * client,u16 addr,u32 value)86cb7a01acSMauro Carvalho Chehab int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
87cb7a01acSMauro Carvalho Chehab {
88cb7a01acSMauro Carvalho Chehab 	u8 buffer[6];
8910a34367SMauro Carvalho Chehab 
90cb7a01acSMauro Carvalho Chehab 	buffer[0] = addr >> 8;
91cb7a01acSMauro Carvalho Chehab 	buffer[1] = addr & 0xff;
92cb7a01acSMauro Carvalho Chehab 	buffer[2] = value & 0xff;
93cb7a01acSMauro Carvalho Chehab 	buffer[3] = (value >> 8) & 0xff;
94cb7a01acSMauro Carvalho Chehab 	buffer[4] = (value >> 16) & 0xff;
95cb7a01acSMauro Carvalho Chehab 	buffer[5] = value >> 24;
96cb7a01acSMauro Carvalho Chehab 	return i2c_master_send(client, buffer, 6);
97cb7a01acSMauro Carvalho Chehab }
98cb7a01acSMauro Carvalho Chehab 
cx25840_read(struct i2c_client * client,u16 addr)99cb7a01acSMauro Carvalho Chehab u8 cx25840_read(struct i2c_client *client, u16 addr)
100cb7a01acSMauro Carvalho Chehab {
101cb7a01acSMauro Carvalho Chehab 	struct i2c_msg msgs[2];
102cb7a01acSMauro Carvalho Chehab 	u8 tx_buf[2], rx_buf[1];
103cb7a01acSMauro Carvalho Chehab 
104cb7a01acSMauro Carvalho Chehab 	/* Write register address */
105cb7a01acSMauro Carvalho Chehab 	tx_buf[0] = addr >> 8;
106cb7a01acSMauro Carvalho Chehab 	tx_buf[1] = addr & 0xff;
107cb7a01acSMauro Carvalho Chehab 	msgs[0].addr = client->addr;
108cb7a01acSMauro Carvalho Chehab 	msgs[0].flags = 0;
109cb7a01acSMauro Carvalho Chehab 	msgs[0].len = 2;
110cb7a01acSMauro Carvalho Chehab 	msgs[0].buf = (char *)tx_buf;
111cb7a01acSMauro Carvalho Chehab 
112cb7a01acSMauro Carvalho Chehab 	/* Read data from register */
113cb7a01acSMauro Carvalho Chehab 	msgs[1].addr = client->addr;
114cb7a01acSMauro Carvalho Chehab 	msgs[1].flags = I2C_M_RD;
115cb7a01acSMauro Carvalho Chehab 	msgs[1].len = 1;
116cb7a01acSMauro Carvalho Chehab 	msgs[1].buf = (char *)rx_buf;
117cb7a01acSMauro Carvalho Chehab 
118cb7a01acSMauro Carvalho Chehab 	if (i2c_transfer(client->adapter, msgs, 2) < 2)
119cb7a01acSMauro Carvalho Chehab 		return 0;
120cb7a01acSMauro Carvalho Chehab 
121cb7a01acSMauro Carvalho Chehab 	return rx_buf[0];
122cb7a01acSMauro Carvalho Chehab }
123cb7a01acSMauro Carvalho Chehab 
cx25840_read4(struct i2c_client * client,u16 addr)124cb7a01acSMauro Carvalho Chehab u32 cx25840_read4(struct i2c_client *client, u16 addr)
125cb7a01acSMauro Carvalho Chehab {
126cb7a01acSMauro Carvalho Chehab 	struct i2c_msg msgs[2];
127cb7a01acSMauro Carvalho Chehab 	u8 tx_buf[2], rx_buf[4];
128cb7a01acSMauro Carvalho Chehab 
129cb7a01acSMauro Carvalho Chehab 	/* Write register address */
130cb7a01acSMauro Carvalho Chehab 	tx_buf[0] = addr >> 8;
131cb7a01acSMauro Carvalho Chehab 	tx_buf[1] = addr & 0xff;
132cb7a01acSMauro Carvalho Chehab 	msgs[0].addr = client->addr;
133cb7a01acSMauro Carvalho Chehab 	msgs[0].flags = 0;
134cb7a01acSMauro Carvalho Chehab 	msgs[0].len = 2;
135cb7a01acSMauro Carvalho Chehab 	msgs[0].buf = (char *)tx_buf;
136cb7a01acSMauro Carvalho Chehab 
137cb7a01acSMauro Carvalho Chehab 	/* Read data from registers */
138cb7a01acSMauro Carvalho Chehab 	msgs[1].addr = client->addr;
139cb7a01acSMauro Carvalho Chehab 	msgs[1].flags = I2C_M_RD;
140cb7a01acSMauro Carvalho Chehab 	msgs[1].len = 4;
141cb7a01acSMauro Carvalho Chehab 	msgs[1].buf = (char *)rx_buf;
142cb7a01acSMauro Carvalho Chehab 
143cb7a01acSMauro Carvalho Chehab 	if (i2c_transfer(client->adapter, msgs, 2) < 2)
144cb7a01acSMauro Carvalho Chehab 		return 0;
145cb7a01acSMauro Carvalho Chehab 
146cb7a01acSMauro Carvalho Chehab 	return (rx_buf[3] << 24) | (rx_buf[2] << 16) | (rx_buf[1] << 8) |
147cb7a01acSMauro Carvalho Chehab 		rx_buf[0];
148cb7a01acSMauro Carvalho Chehab }
149cb7a01acSMauro Carvalho Chehab 
cx25840_and_or(struct i2c_client * client,u16 addr,unsigned int and_mask,u8 or_value)15010a34367SMauro Carvalho Chehab int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned int and_mask,
151cb7a01acSMauro Carvalho Chehab 		   u8 or_value)
152cb7a01acSMauro Carvalho Chehab {
153cb7a01acSMauro Carvalho Chehab 	return cx25840_write(client, addr,
154cb7a01acSMauro Carvalho Chehab 			     (cx25840_read(client, addr) & and_mask) |
155cb7a01acSMauro Carvalho Chehab 			     or_value);
156cb7a01acSMauro Carvalho Chehab }
157cb7a01acSMauro Carvalho Chehab 
cx25840_and_or4(struct i2c_client * client,u16 addr,u32 and_mask,u32 or_value)158cb7a01acSMauro Carvalho Chehab int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
159cb7a01acSMauro Carvalho Chehab 		    u32 or_value)
160cb7a01acSMauro Carvalho Chehab {
161cb7a01acSMauro Carvalho Chehab 	return cx25840_write4(client, addr,
162cb7a01acSMauro Carvalho Chehab 			      (cx25840_read4(client, addr) & and_mask) |
163cb7a01acSMauro Carvalho Chehab 			      or_value);
164cb7a01acSMauro Carvalho Chehab }
165cb7a01acSMauro Carvalho Chehab 
166cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
167cb7a01acSMauro Carvalho Chehab 
16810a34367SMauro Carvalho Chehab static int set_input(struct i2c_client *client,
16910a34367SMauro Carvalho Chehab 		     enum cx25840_video_input vid_input,
170cb7a01acSMauro Carvalho Chehab 		     enum cx25840_audio_input aud_input);
171cb7a01acSMauro Carvalho Chehab 
172cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
173cb7a01acSMauro Carvalho Chehab 
cx23885_s_io_pin_config(struct v4l2_subdev * sd,size_t n,struct v4l2_subdev_io_pin_config * p)174cb7a01acSMauro Carvalho Chehab static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
175cb7a01acSMauro Carvalho Chehab 				   struct v4l2_subdev_io_pin_config *p)
176cb7a01acSMauro Carvalho Chehab {
177cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
178cb7a01acSMauro Carvalho Chehab 	int i;
179cb7a01acSMauro Carvalho Chehab 	u32 pin_ctrl;
180cb7a01acSMauro Carvalho Chehab 	u8 gpio_oe, gpio_data, strength;
181cb7a01acSMauro Carvalho Chehab 
182cb7a01acSMauro Carvalho Chehab 	pin_ctrl = cx25840_read4(client, 0x120);
183cb7a01acSMauro Carvalho Chehab 	gpio_oe = cx25840_read(client, 0x160);
184cb7a01acSMauro Carvalho Chehab 	gpio_data = cx25840_read(client, 0x164);
185cb7a01acSMauro Carvalho Chehab 
186cb7a01acSMauro Carvalho Chehab 	for (i = 0; i < n; i++) {
187cb7a01acSMauro Carvalho Chehab 		strength = p[i].strength;
188cb7a01acSMauro Carvalho Chehab 		if (strength > CX25840_PIN_DRIVE_FAST)
189cb7a01acSMauro Carvalho Chehab 			strength = CX25840_PIN_DRIVE_FAST;
190cb7a01acSMauro Carvalho Chehab 
191cb7a01acSMauro Carvalho Chehab 		switch (p[i].pin) {
192cb7a01acSMauro Carvalho Chehab 		case CX23885_PIN_IRQ_N_GPIO16:
193cb7a01acSMauro Carvalho Chehab 			if (p[i].function != CX23885_PAD_IRQ_N) {
194cb7a01acSMauro Carvalho Chehab 				/* GPIO16 */
195cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x1 << 25);
196cb7a01acSMauro Carvalho Chehab 			} else {
197cb7a01acSMauro Carvalho Chehab 				/* IRQ_N */
198cb7a01acSMauro Carvalho Chehab 				if (p[i].flags &
1994eb2f557SMauro Carvalho Chehab 					(BIT(V4L2_SUBDEV_IO_PIN_DISABLE) |
2004eb2f557SMauro Carvalho Chehab 					 BIT(V4L2_SUBDEV_IO_PIN_INPUT))) {
201cb7a01acSMauro Carvalho Chehab 					pin_ctrl &= ~(0x1 << 25);
202cb7a01acSMauro Carvalho Chehab 				} else {
203cb7a01acSMauro Carvalho Chehab 					pin_ctrl |= (0x1 << 25);
204cb7a01acSMauro Carvalho Chehab 				}
205cb7a01acSMauro Carvalho Chehab 				if (p[i].flags &
2064eb2f557SMauro Carvalho Chehab 					BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW)) {
207cb7a01acSMauro Carvalho Chehab 					pin_ctrl &= ~(0x1 << 24);
208cb7a01acSMauro Carvalho Chehab 				} else {
209cb7a01acSMauro Carvalho Chehab 					pin_ctrl |= (0x1 << 24);
210cb7a01acSMauro Carvalho Chehab 				}
211cb7a01acSMauro Carvalho Chehab 			}
212cb7a01acSMauro Carvalho Chehab 			break;
213cb7a01acSMauro Carvalho Chehab 		case CX23885_PIN_IR_RX_GPIO19:
214cb7a01acSMauro Carvalho Chehab 			if (p[i].function != CX23885_PAD_GPIO19) {
215cb7a01acSMauro Carvalho Chehab 				/* IR_RX */
216cb7a01acSMauro Carvalho Chehab 				gpio_oe |= (0x1 << 0);
217cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x3 << 18);
218cb7a01acSMauro Carvalho Chehab 				pin_ctrl |= (strength << 18);
219cb7a01acSMauro Carvalho Chehab 			} else {
220cb7a01acSMauro Carvalho Chehab 				/* GPIO19 */
221cb7a01acSMauro Carvalho Chehab 				gpio_oe &= ~(0x1 << 0);
2224eb2f557SMauro Carvalho Chehab 				if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
223cb7a01acSMauro Carvalho Chehab 					gpio_data &= ~(0x1 << 0);
224cb7a01acSMauro Carvalho Chehab 					gpio_data |= ((p[i].value & 0x1) << 0);
225cb7a01acSMauro Carvalho Chehab 				}
226cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x3 << 12);
227cb7a01acSMauro Carvalho Chehab 				pin_ctrl |= (strength << 12);
228cb7a01acSMauro Carvalho Chehab 			}
229cb7a01acSMauro Carvalho Chehab 			break;
230cb7a01acSMauro Carvalho Chehab 		case CX23885_PIN_IR_TX_GPIO20:
231cb7a01acSMauro Carvalho Chehab 			if (p[i].function != CX23885_PAD_GPIO20) {
232cb7a01acSMauro Carvalho Chehab 				/* IR_TX */
233cb7a01acSMauro Carvalho Chehab 				gpio_oe |= (0x1 << 1);
2344eb2f557SMauro Carvalho Chehab 				if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
235cb7a01acSMauro Carvalho Chehab 					pin_ctrl &= ~(0x1 << 10);
236cb7a01acSMauro Carvalho Chehab 				else
237cb7a01acSMauro Carvalho Chehab 					pin_ctrl |= (0x1 << 10);
238cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x3 << 18);
239cb7a01acSMauro Carvalho Chehab 				pin_ctrl |= (strength << 18);
240cb7a01acSMauro Carvalho Chehab 			} else {
241cb7a01acSMauro Carvalho Chehab 				/* GPIO20 */
242cb7a01acSMauro Carvalho Chehab 				gpio_oe &= ~(0x1 << 1);
2434eb2f557SMauro Carvalho Chehab 				if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
244cb7a01acSMauro Carvalho Chehab 					gpio_data &= ~(0x1 << 1);
245cb7a01acSMauro Carvalho Chehab 					gpio_data |= ((p[i].value & 0x1) << 1);
246cb7a01acSMauro Carvalho Chehab 				}
247cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x3 << 12);
248cb7a01acSMauro Carvalho Chehab 				pin_ctrl |= (strength << 12);
249cb7a01acSMauro Carvalho Chehab 			}
250cb7a01acSMauro Carvalho Chehab 			break;
251cb7a01acSMauro Carvalho Chehab 		case CX23885_PIN_I2S_SDAT_GPIO21:
252cb7a01acSMauro Carvalho Chehab 			if (p[i].function != CX23885_PAD_GPIO21) {
253cb7a01acSMauro Carvalho Chehab 				/* I2S_SDAT */
254cb7a01acSMauro Carvalho Chehab 				/* TODO: Input or Output config */
255cb7a01acSMauro Carvalho Chehab 				gpio_oe |= (0x1 << 2);
256cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x3 << 22);
257cb7a01acSMauro Carvalho Chehab 				pin_ctrl |= (strength << 22);
258cb7a01acSMauro Carvalho Chehab 			} else {
259cb7a01acSMauro Carvalho Chehab 				/* GPIO21 */
260cb7a01acSMauro Carvalho Chehab 				gpio_oe &= ~(0x1 << 2);
2614eb2f557SMauro Carvalho Chehab 				if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
262cb7a01acSMauro Carvalho Chehab 					gpio_data &= ~(0x1 << 2);
263cb7a01acSMauro Carvalho Chehab 					gpio_data |= ((p[i].value & 0x1) << 2);
264cb7a01acSMauro Carvalho Chehab 				}
265cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x3 << 12);
266cb7a01acSMauro Carvalho Chehab 				pin_ctrl |= (strength << 12);
267cb7a01acSMauro Carvalho Chehab 			}
268cb7a01acSMauro Carvalho Chehab 			break;
269cb7a01acSMauro Carvalho Chehab 		case CX23885_PIN_I2S_WCLK_GPIO22:
270cb7a01acSMauro Carvalho Chehab 			if (p[i].function != CX23885_PAD_GPIO22) {
271cb7a01acSMauro Carvalho Chehab 				/* I2S_WCLK */
272cb7a01acSMauro Carvalho Chehab 				/* TODO: Input or Output config */
273cb7a01acSMauro Carvalho Chehab 				gpio_oe |= (0x1 << 3);
274cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x3 << 22);
275cb7a01acSMauro Carvalho Chehab 				pin_ctrl |= (strength << 22);
276cb7a01acSMauro Carvalho Chehab 			} else {
277cb7a01acSMauro Carvalho Chehab 				/* GPIO22 */
278cb7a01acSMauro Carvalho Chehab 				gpio_oe &= ~(0x1 << 3);
2794eb2f557SMauro Carvalho Chehab 				if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
280cb7a01acSMauro Carvalho Chehab 					gpio_data &= ~(0x1 << 3);
281cb7a01acSMauro Carvalho Chehab 					gpio_data |= ((p[i].value & 0x1) << 3);
282cb7a01acSMauro Carvalho Chehab 				}
283cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x3 << 12);
284cb7a01acSMauro Carvalho Chehab 				pin_ctrl |= (strength << 12);
285cb7a01acSMauro Carvalho Chehab 			}
286cb7a01acSMauro Carvalho Chehab 			break;
287cb7a01acSMauro Carvalho Chehab 		case CX23885_PIN_I2S_BCLK_GPIO23:
288cb7a01acSMauro Carvalho Chehab 			if (p[i].function != CX23885_PAD_GPIO23) {
289cb7a01acSMauro Carvalho Chehab 				/* I2S_BCLK */
290cb7a01acSMauro Carvalho Chehab 				/* TODO: Input or Output config */
291cb7a01acSMauro Carvalho Chehab 				gpio_oe |= (0x1 << 4);
292cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x3 << 22);
293cb7a01acSMauro Carvalho Chehab 				pin_ctrl |= (strength << 22);
294cb7a01acSMauro Carvalho Chehab 			} else {
295cb7a01acSMauro Carvalho Chehab 				/* GPIO23 */
296cb7a01acSMauro Carvalho Chehab 				gpio_oe &= ~(0x1 << 4);
2974eb2f557SMauro Carvalho Chehab 				if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) {
298cb7a01acSMauro Carvalho Chehab 					gpio_data &= ~(0x1 << 4);
299cb7a01acSMauro Carvalho Chehab 					gpio_data |= ((p[i].value & 0x1) << 4);
300cb7a01acSMauro Carvalho Chehab 				}
301cb7a01acSMauro Carvalho Chehab 				pin_ctrl &= ~(0x3 << 12);
302cb7a01acSMauro Carvalho Chehab 				pin_ctrl |= (strength << 12);
303cb7a01acSMauro Carvalho Chehab 			}
304cb7a01acSMauro Carvalho Chehab 			break;
305cb7a01acSMauro Carvalho Chehab 		}
306cb7a01acSMauro Carvalho Chehab 	}
307cb7a01acSMauro Carvalho Chehab 
308cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x164, gpio_data);
309cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x160, gpio_oe);
310cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x120, pin_ctrl);
311cb7a01acSMauro Carvalho Chehab 	return 0;
312cb7a01acSMauro Carvalho Chehab }
313cb7a01acSMauro Carvalho Chehab 
cx25840_function_to_pad(struct i2c_client * client,u8 function)314e81a9076SMaciej S. Szmigiero static u8 cx25840_function_to_pad(struct i2c_client *client, u8 function)
315e81a9076SMaciej S. Szmigiero {
316e81a9076SMaciej S. Szmigiero 	if (function > CX25840_PAD_VRESET) {
317e81a9076SMaciej S. Szmigiero 		v4l_err(client, "invalid function %u, assuming default\n",
318e81a9076SMaciej S. Szmigiero 			(unsigned int)function);
319e81a9076SMaciej S. Szmigiero 		return 0;
320e81a9076SMaciej S. Szmigiero 	}
321e81a9076SMaciej S. Szmigiero 
322e81a9076SMaciej S. Szmigiero 	return function;
323e81a9076SMaciej S. Szmigiero }
324e81a9076SMaciej S. Szmigiero 
cx25840_set_invert(u8 * pinctrl3,u8 * voutctrl4,u8 function,u8 pin,bool invert)325e81a9076SMaciej S. Szmigiero static void cx25840_set_invert(u8 *pinctrl3, u8 *voutctrl4, u8 function,
326e81a9076SMaciej S. Szmigiero 			       u8 pin, bool invert)
327e81a9076SMaciej S. Szmigiero {
328e81a9076SMaciej S. Szmigiero 	switch (function) {
329e81a9076SMaciej S. Szmigiero 	case CX25840_PAD_IRQ_N:
330e81a9076SMaciej S. Szmigiero 		if (invert)
331e81a9076SMaciej S. Szmigiero 			*pinctrl3 &= ~2;
332e81a9076SMaciej S. Szmigiero 		else
333e81a9076SMaciej S. Szmigiero 			*pinctrl3 |= 2;
334e81a9076SMaciej S. Szmigiero 		break;
335e81a9076SMaciej S. Szmigiero 
336e81a9076SMaciej S. Szmigiero 	case CX25840_PAD_ACTIVE:
337e81a9076SMaciej S. Szmigiero 		if (invert)
338e81a9076SMaciej S. Szmigiero 			*voutctrl4 |= BIT(2);
339e81a9076SMaciej S. Szmigiero 		else
340e81a9076SMaciej S. Szmigiero 			*voutctrl4 &= ~BIT(2);
341e81a9076SMaciej S. Szmigiero 		break;
342e81a9076SMaciej S. Szmigiero 
343e81a9076SMaciej S. Szmigiero 	case CX25840_PAD_VACTIVE:
344e81a9076SMaciej S. Szmigiero 		if (invert)
345e81a9076SMaciej S. Szmigiero 			*voutctrl4 |= BIT(5);
346e81a9076SMaciej S. Szmigiero 		else
347e81a9076SMaciej S. Szmigiero 			*voutctrl4 &= ~BIT(5);
348e81a9076SMaciej S. Szmigiero 		break;
349e81a9076SMaciej S. Szmigiero 
350e81a9076SMaciej S. Szmigiero 	case CX25840_PAD_CBFLAG:
351e81a9076SMaciej S. Szmigiero 		if (invert)
352e81a9076SMaciej S. Szmigiero 			*voutctrl4 |= BIT(4);
353e81a9076SMaciej S. Szmigiero 		else
354e81a9076SMaciej S. Szmigiero 			*voutctrl4 &= ~BIT(4);
355e81a9076SMaciej S. Szmigiero 		break;
356e81a9076SMaciej S. Szmigiero 
357e81a9076SMaciej S. Szmigiero 	case CX25840_PAD_VRESET:
358e81a9076SMaciej S. Szmigiero 		if (invert)
359e81a9076SMaciej S. Szmigiero 			*voutctrl4 |= BIT(0);
360e81a9076SMaciej S. Szmigiero 		else
361e81a9076SMaciej S. Szmigiero 			*voutctrl4 &= ~BIT(0);
362e81a9076SMaciej S. Szmigiero 		break;
363e81a9076SMaciej S. Szmigiero 	}
364e81a9076SMaciej S. Szmigiero 
365e81a9076SMaciej S. Szmigiero 	if (function != CX25840_PAD_DEFAULT)
366e81a9076SMaciej S. Szmigiero 		return;
367e81a9076SMaciej S. Szmigiero 
368e81a9076SMaciej S. Szmigiero 	switch (pin) {
369e81a9076SMaciej S. Szmigiero 	case CX25840_PIN_DVALID_PRGM0:
370e81a9076SMaciej S. Szmigiero 		if (invert)
371e81a9076SMaciej S. Szmigiero 			*voutctrl4 |= BIT(6);
372e81a9076SMaciej S. Szmigiero 		else
373e81a9076SMaciej S. Szmigiero 			*voutctrl4 &= ~BIT(6);
374e81a9076SMaciej S. Szmigiero 		break;
375e81a9076SMaciej S. Szmigiero 
376e81a9076SMaciej S. Szmigiero 	case CX25840_PIN_HRESET_PRGM2:
377e81a9076SMaciej S. Szmigiero 		if (invert)
378e81a9076SMaciej S. Szmigiero 			*voutctrl4 |= BIT(1);
379e81a9076SMaciej S. Szmigiero 		else
380e81a9076SMaciej S. Szmigiero 			*voutctrl4 &= ~BIT(1);
381e81a9076SMaciej S. Szmigiero 		break;
382e81a9076SMaciej S. Szmigiero 	}
383e81a9076SMaciej S. Szmigiero }
384e81a9076SMaciej S. Szmigiero 
cx25840_s_io_pin_config(struct v4l2_subdev * sd,size_t n,struct v4l2_subdev_io_pin_config * p)385e81a9076SMaciej S. Szmigiero static int cx25840_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
386e81a9076SMaciej S. Szmigiero 				   struct v4l2_subdev_io_pin_config *p)
387e81a9076SMaciej S. Szmigiero {
388e81a9076SMaciej S. Szmigiero 	struct i2c_client *client = v4l2_get_subdevdata(sd);
389e81a9076SMaciej S. Szmigiero 	unsigned int i;
390e81a9076SMaciej S. Szmigiero 	u8 pinctrl[6], pinconf[10], voutctrl4;
391e81a9076SMaciej S. Szmigiero 
392e81a9076SMaciej S. Szmigiero 	for (i = 0; i < 6; i++)
393e81a9076SMaciej S. Szmigiero 		pinctrl[i] = cx25840_read(client, 0x114 + i);
394e81a9076SMaciej S. Szmigiero 
395e81a9076SMaciej S. Szmigiero 	for (i = 0; i < 10; i++)
396e81a9076SMaciej S. Szmigiero 		pinconf[i] = cx25840_read(client, 0x11c + i);
397e81a9076SMaciej S. Szmigiero 
398e81a9076SMaciej S. Szmigiero 	voutctrl4 = cx25840_read(client, 0x407);
399e81a9076SMaciej S. Szmigiero 
400e81a9076SMaciej S. Szmigiero 	for (i = 0; i < n; i++) {
401e81a9076SMaciej S. Szmigiero 		u8 strength = p[i].strength;
402e81a9076SMaciej S. Szmigiero 
403e81a9076SMaciej S. Szmigiero 		if (strength != CX25840_PIN_DRIVE_SLOW &&
404e81a9076SMaciej S. Szmigiero 		    strength != CX25840_PIN_DRIVE_MEDIUM &&
405e81a9076SMaciej S. Szmigiero 		    strength != CX25840_PIN_DRIVE_FAST) {
406e81a9076SMaciej S. Szmigiero 			v4l_err(client,
407e81a9076SMaciej S. Szmigiero 				"invalid drive speed for pin %u (%u), assuming fast\n",
408e81a9076SMaciej S. Szmigiero 				(unsigned int)p[i].pin,
409e81a9076SMaciej S. Szmigiero 				(unsigned int)strength);
410e81a9076SMaciej S. Szmigiero 
411e81a9076SMaciej S. Szmigiero 			strength = CX25840_PIN_DRIVE_FAST;
412e81a9076SMaciej S. Szmigiero 		}
413e81a9076SMaciej S. Szmigiero 
414e81a9076SMaciej S. Szmigiero 		switch (p[i].pin) {
415e81a9076SMaciej S. Szmigiero 		case CX25840_PIN_DVALID_PRGM0:
416e81a9076SMaciej S. Szmigiero 			if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
417e81a9076SMaciej S. Szmigiero 				pinctrl[0] &= ~BIT(6);
418e81a9076SMaciej S. Szmigiero 			else
419e81a9076SMaciej S. Szmigiero 				pinctrl[0] |= BIT(6);
420e81a9076SMaciej S. Szmigiero 
421e81a9076SMaciej S. Szmigiero 			pinconf[3] &= 0xf0;
422e81a9076SMaciej S. Szmigiero 			pinconf[3] |= cx25840_function_to_pad(client,
423e81a9076SMaciej S. Szmigiero 							      p[i].function);
424e81a9076SMaciej S. Szmigiero 
425e81a9076SMaciej S. Szmigiero 			cx25840_set_invert(&pinctrl[3], &voutctrl4,
426e81a9076SMaciej S. Szmigiero 					   p[i].function,
427e81a9076SMaciej S. Szmigiero 					   CX25840_PIN_DVALID_PRGM0,
428e81a9076SMaciej S. Szmigiero 					   p[i].flags &
429e81a9076SMaciej S. Szmigiero 					   BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW));
430e81a9076SMaciej S. Szmigiero 
431e81a9076SMaciej S. Szmigiero 			pinctrl[4] &= ~(3 << 2); /* CX25840_PIN_DRIVE_MEDIUM */
432e81a9076SMaciej S. Szmigiero 			switch (strength) {
433e81a9076SMaciej S. Szmigiero 			case CX25840_PIN_DRIVE_SLOW:
434e81a9076SMaciej S. Szmigiero 				pinctrl[4] |= 1 << 2;
435e81a9076SMaciej S. Szmigiero 				break;
436e81a9076SMaciej S. Szmigiero 
437e81a9076SMaciej S. Szmigiero 			case CX25840_PIN_DRIVE_FAST:
438e81a9076SMaciej S. Szmigiero 				pinctrl[4] |= 2 << 2;
439e81a9076SMaciej S. Szmigiero 				break;
440e81a9076SMaciej S. Szmigiero 			}
441e81a9076SMaciej S. Szmigiero 
442e81a9076SMaciej S. Szmigiero 			break;
443e81a9076SMaciej S. Szmigiero 
444e81a9076SMaciej S. Szmigiero 		case CX25840_PIN_HRESET_PRGM2:
445e81a9076SMaciej S. Szmigiero 			if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
446e81a9076SMaciej S. Szmigiero 				pinctrl[1] &= ~BIT(0);
447e81a9076SMaciej S. Szmigiero 			else
448e81a9076SMaciej S. Szmigiero 				pinctrl[1] |= BIT(0);
449e81a9076SMaciej S. Szmigiero 
450e81a9076SMaciej S. Szmigiero 			pinconf[4] &= 0xf0;
451e81a9076SMaciej S. Szmigiero 			pinconf[4] |= cx25840_function_to_pad(client,
452e81a9076SMaciej S. Szmigiero 							      p[i].function);
453e81a9076SMaciej S. Szmigiero 
454e81a9076SMaciej S. Szmigiero 			cx25840_set_invert(&pinctrl[3], &voutctrl4,
455e81a9076SMaciej S. Szmigiero 					   p[i].function,
456e81a9076SMaciej S. Szmigiero 					   CX25840_PIN_HRESET_PRGM2,
457e81a9076SMaciej S. Szmigiero 					   p[i].flags &
458e81a9076SMaciej S. Szmigiero 					   BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW));
459e81a9076SMaciej S. Szmigiero 
460e81a9076SMaciej S. Szmigiero 			pinctrl[4] &= ~(3 << 2); /* CX25840_PIN_DRIVE_MEDIUM */
461e81a9076SMaciej S. Szmigiero 			switch (strength) {
462e81a9076SMaciej S. Szmigiero 			case CX25840_PIN_DRIVE_SLOW:
463e81a9076SMaciej S. Szmigiero 				pinctrl[4] |= 1 << 2;
464e81a9076SMaciej S. Szmigiero 				break;
465e81a9076SMaciej S. Szmigiero 
466e81a9076SMaciej S. Szmigiero 			case CX25840_PIN_DRIVE_FAST:
467e81a9076SMaciej S. Szmigiero 				pinctrl[4] |= 2 << 2;
468e81a9076SMaciej S. Szmigiero 				break;
469e81a9076SMaciej S. Szmigiero 			}
470e81a9076SMaciej S. Szmigiero 
471e81a9076SMaciej S. Szmigiero 			break;
472e81a9076SMaciej S. Szmigiero 
473e81a9076SMaciej S. Szmigiero 		case CX25840_PIN_PLL_CLK_PRGM7:
474e81a9076SMaciej S. Szmigiero 			if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE))
475e81a9076SMaciej S. Szmigiero 				pinctrl[2] &= ~BIT(2);
476e81a9076SMaciej S. Szmigiero 			else
477e81a9076SMaciej S. Szmigiero 				pinctrl[2] |= BIT(2);
478e81a9076SMaciej S. Szmigiero 
479e81a9076SMaciej S. Szmigiero 			switch (p[i].function) {
480e81a9076SMaciej S. Szmigiero 			case CX25840_PAD_XTI_X5_DLL:
481e81a9076SMaciej S. Szmigiero 				pinconf[6] = 0;
482e81a9076SMaciej S. Szmigiero 				break;
483e81a9076SMaciej S. Szmigiero 
484e81a9076SMaciej S. Szmigiero 			case CX25840_PAD_AUX_PLL:
485e81a9076SMaciej S. Szmigiero 				pinconf[6] = 1;
486e81a9076SMaciej S. Szmigiero 				break;
487e81a9076SMaciej S. Szmigiero 
488e81a9076SMaciej S. Szmigiero 			case CX25840_PAD_VID_PLL:
489e81a9076SMaciej S. Szmigiero 				pinconf[6] = 5;
490e81a9076SMaciej S. Szmigiero 				break;
491e81a9076SMaciej S. Szmigiero 
492e81a9076SMaciej S. Szmigiero 			case CX25840_PAD_XTI:
493e81a9076SMaciej S. Szmigiero 				pinconf[6] = 2;
494e81a9076SMaciej S. Szmigiero 				break;
495e81a9076SMaciej S. Szmigiero 
496e81a9076SMaciej S. Szmigiero 			default:
497e81a9076SMaciej S. Szmigiero 				pinconf[6] = 3;
498e81a9076SMaciej S. Szmigiero 				pinconf[6] |=
499e81a9076SMaciej S. Szmigiero 					cx25840_function_to_pad(client,
500e81a9076SMaciej S. Szmigiero 								p[i].function)
501e81a9076SMaciej S. Szmigiero 					<< 4;
502e81a9076SMaciej S. Szmigiero 			}
503e81a9076SMaciej S. Szmigiero 
504e81a9076SMaciej S. Szmigiero 			break;
505e81a9076SMaciej S. Szmigiero 
506e81a9076SMaciej S. Szmigiero 		default:
507e81a9076SMaciej S. Szmigiero 			v4l_err(client, "invalid or unsupported pin %u\n",
508e81a9076SMaciej S. Szmigiero 				(unsigned int)p[i].pin);
509e81a9076SMaciej S. Szmigiero 			break;
510e81a9076SMaciej S. Szmigiero 		}
511e81a9076SMaciej S. Szmigiero 	}
512e81a9076SMaciej S. Szmigiero 
513e81a9076SMaciej S. Szmigiero 	cx25840_write(client, 0x407, voutctrl4);
514e81a9076SMaciej S. Szmigiero 
515e81a9076SMaciej S. Szmigiero 	for (i = 0; i < 6; i++)
516e81a9076SMaciej S. Szmigiero 		cx25840_write(client, 0x114 + i, pinctrl[i]);
517e81a9076SMaciej S. Szmigiero 
518e81a9076SMaciej S. Szmigiero 	for (i = 0; i < 10; i++)
519e81a9076SMaciej S. Szmigiero 		cx25840_write(client, 0x11c + i, pinconf[i]);
520e81a9076SMaciej S. Szmigiero 
521e81a9076SMaciej S. Szmigiero 	return 0;
522e81a9076SMaciej S. Szmigiero }
523e81a9076SMaciej S. Szmigiero 
common_s_io_pin_config(struct v4l2_subdev * sd,size_t n,struct v4l2_subdev_io_pin_config * pincfg)524cb7a01acSMauro Carvalho Chehab static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
525cb7a01acSMauro Carvalho Chehab 				  struct v4l2_subdev_io_pin_config *pincfg)
526cb7a01acSMauro Carvalho Chehab {
527cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
528cb7a01acSMauro Carvalho Chehab 
529cb7a01acSMauro Carvalho Chehab 	if (is_cx2388x(state))
530cb7a01acSMauro Carvalho Chehab 		return cx23885_s_io_pin_config(sd, n, pincfg);
531e81a9076SMaciej S. Szmigiero 	else if (is_cx2584x(state))
532e81a9076SMaciej S. Szmigiero 		return cx25840_s_io_pin_config(sd, n, pincfg);
533cb7a01acSMauro Carvalho Chehab 	return 0;
534cb7a01acSMauro Carvalho Chehab }
535cb7a01acSMauro Carvalho Chehab 
536cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
537cb7a01acSMauro Carvalho Chehab 
init_dll1(struct i2c_client * client)538cb7a01acSMauro Carvalho Chehab static void init_dll1(struct i2c_client *client)
539cb7a01acSMauro Carvalho Chehab {
54010a34367SMauro Carvalho Chehab 	/*
54110a34367SMauro Carvalho Chehab 	 * This is the Hauppauge sequence used to
54210a34367SMauro Carvalho Chehab 	 * initialize the Delay Lock Loop 1 (ADC DLL).
54310a34367SMauro Carvalho Chehab 	 */
544cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x159, 0x23);
545cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x15a, 0x87);
546cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x15b, 0x06);
547cb7a01acSMauro Carvalho Chehab 	udelay(10);
548cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x159, 0xe1);
549cb7a01acSMauro Carvalho Chehab 	udelay(10);
550cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x15a, 0x86);
551cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x159, 0xe0);
552cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x159, 0xe1);
553cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x15b, 0x10);
554cb7a01acSMauro Carvalho Chehab }
555cb7a01acSMauro Carvalho Chehab 
init_dll2(struct i2c_client * client)556cb7a01acSMauro Carvalho Chehab static void init_dll2(struct i2c_client *client)
557cb7a01acSMauro Carvalho Chehab {
55810a34367SMauro Carvalho Chehab 	/*
55910a34367SMauro Carvalho Chehab 	 * This is the Hauppauge sequence used to
56010a34367SMauro Carvalho Chehab 	 * initialize the Delay Lock Loop 2 (ADC DLL).
56110a34367SMauro Carvalho Chehab 	 */
562cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x15d, 0xe3);
563cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x15e, 0x86);
564cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x15f, 0x06);
565cb7a01acSMauro Carvalho Chehab 	udelay(10);
566cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x15d, 0xe1);
567cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x15d, 0xe0);
568cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x15d, 0xe1);
569cb7a01acSMauro Carvalho Chehab }
570cb7a01acSMauro Carvalho Chehab 
cx25836_initialize(struct i2c_client * client)571cb7a01acSMauro Carvalho Chehab static void cx25836_initialize(struct i2c_client *client)
572cb7a01acSMauro Carvalho Chehab {
57310a34367SMauro Carvalho Chehab 	/*
57410a34367SMauro Carvalho Chehab 	 *reset configuration is described on page 3-77
57510a34367SMauro Carvalho Chehab 	 * of the CX25836 datasheet
57610a34367SMauro Carvalho Chehab 	 */
57710a34367SMauro Carvalho Chehab 
578cb7a01acSMauro Carvalho Chehab 	/* 2. */
579cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x000, ~0x01, 0x01);
580cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x000, ~0x01, 0x00);
581cb7a01acSMauro Carvalho Chehab 	/* 3a. */
582cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x15a, ~0x70, 0x00);
583cb7a01acSMauro Carvalho Chehab 	/* 3b. */
584cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x15b, ~0x1e, 0x06);
585cb7a01acSMauro Carvalho Chehab 	/* 3c. */
586cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x159, ~0x02, 0x02);
587cb7a01acSMauro Carvalho Chehab 	/* 3d. */
588cb7a01acSMauro Carvalho Chehab 	udelay(10);
589cb7a01acSMauro Carvalho Chehab 	/* 3e. */
590cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x159, ~0x02, 0x00);
591cb7a01acSMauro Carvalho Chehab 	/* 3f. */
592cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x159, ~0xc0, 0xc0);
593cb7a01acSMauro Carvalho Chehab 	/* 3g. */
594cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x159, ~0x01, 0x00);
595cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x159, ~0x01, 0x01);
596cb7a01acSMauro Carvalho Chehab 	/* 3h. */
597cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
598cb7a01acSMauro Carvalho Chehab }
599cb7a01acSMauro Carvalho Chehab 
cx25840_work_handler(struct work_struct * work)600cb7a01acSMauro Carvalho Chehab static void cx25840_work_handler(struct work_struct *work)
601cb7a01acSMauro Carvalho Chehab {
602cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work);
60310a34367SMauro Carvalho Chehab 
604cb7a01acSMauro Carvalho Chehab 	cx25840_loadfw(state->c);
605cb7a01acSMauro Carvalho Chehab 	wake_up(&state->fw_wait);
606cb7a01acSMauro Carvalho Chehab }
607cb7a01acSMauro Carvalho Chehab 
608e81a9076SMaciej S. Szmigiero #define CX25840_VCONFIG_SET_BIT(state, opt_msk, voc, idx, bit, oneval)	\
609e81a9076SMaciej S. Szmigiero 	do {								\
610e81a9076SMaciej S. Szmigiero 		if ((state)->vid_config & (opt_msk)) {			\
611e81a9076SMaciej S. Szmigiero 			if (((state)->vid_config & (opt_msk)) ==	\
612e81a9076SMaciej S. Szmigiero 			    (oneval))					\
613e81a9076SMaciej S. Szmigiero 				(voc)[idx] |= BIT(bit);		\
614e81a9076SMaciej S. Szmigiero 			else						\
615e81a9076SMaciej S. Szmigiero 				(voc)[idx] &= ~BIT(bit);		\
616e81a9076SMaciej S. Szmigiero 		}							\
617e81a9076SMaciej S. Szmigiero 	} while (0)
618e81a9076SMaciej S. Szmigiero 
619e81a9076SMaciej S. Szmigiero /* apply current vconfig to hardware regs */
cx25840_vconfig_apply(struct i2c_client * client)620e81a9076SMaciej S. Szmigiero static void cx25840_vconfig_apply(struct i2c_client *client)
621e81a9076SMaciej S. Szmigiero {
622e81a9076SMaciej S. Szmigiero 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
623e81a9076SMaciej S. Szmigiero 	u8 voutctrl[3];
624e81a9076SMaciej S. Szmigiero 	unsigned int i;
625e81a9076SMaciej S. Szmigiero 
626e81a9076SMaciej S. Szmigiero 	for (i = 0; i < 3; i++)
627e81a9076SMaciej S. Szmigiero 		voutctrl[i] = cx25840_read(client, 0x404 + i);
628e81a9076SMaciej S. Szmigiero 
629e81a9076SMaciej S. Szmigiero 	if (state->vid_config & CX25840_VCONFIG_FMT_MASK)
630e81a9076SMaciej S. Szmigiero 		voutctrl[0] &= ~3;
631e81a9076SMaciej S. Szmigiero 	switch (state->vid_config & CX25840_VCONFIG_FMT_MASK) {
632e81a9076SMaciej S. Szmigiero 	case CX25840_VCONFIG_FMT_BT656:
633e81a9076SMaciej S. Szmigiero 		voutctrl[0] |= 1;
634e81a9076SMaciej S. Szmigiero 		break;
635e81a9076SMaciej S. Szmigiero 
636e81a9076SMaciej S. Szmigiero 	case CX25840_VCONFIG_FMT_VIP11:
637e81a9076SMaciej S. Szmigiero 		voutctrl[0] |= 2;
638e81a9076SMaciej S. Szmigiero 		break;
639e81a9076SMaciej S. Szmigiero 
640e81a9076SMaciej S. Szmigiero 	case CX25840_VCONFIG_FMT_VIP2:
641e81a9076SMaciej S. Szmigiero 		voutctrl[0] |= 3;
642e81a9076SMaciej S. Szmigiero 		break;
643e81a9076SMaciej S. Szmigiero 
644e81a9076SMaciej S. Szmigiero 	case CX25840_VCONFIG_FMT_BT601:
645e81a9076SMaciej S. Szmigiero 		/* zero */
646e81a9076SMaciej S. Szmigiero 	default:
647e81a9076SMaciej S. Szmigiero 		break;
648e81a9076SMaciej S. Szmigiero 	}
649e81a9076SMaciej S. Szmigiero 
650e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_RES_MASK, voutctrl,
651e81a9076SMaciej S. Szmigiero 				0, 2, CX25840_VCONFIG_RES_10BIT);
652e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VBIRAW_MASK, voutctrl,
653e81a9076SMaciej S. Szmigiero 				0, 3, CX25840_VCONFIG_VBIRAW_ENABLED);
654e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_ANCDATA_MASK, voutctrl,
655e81a9076SMaciej S. Szmigiero 				0, 4, CX25840_VCONFIG_ANCDATA_ENABLED);
656e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_TASKBIT_MASK, voutctrl,
657e81a9076SMaciej S. Szmigiero 				0, 5, CX25840_VCONFIG_TASKBIT_ONE);
658e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_ACTIVE_MASK, voutctrl,
659e81a9076SMaciej S. Szmigiero 				1, 2, CX25840_VCONFIG_ACTIVE_HORIZONTAL);
660e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VALID_MASK, voutctrl,
661e81a9076SMaciej S. Szmigiero 				1, 3, CX25840_VCONFIG_VALID_ANDACTIVE);
662e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_HRESETW_MASK, voutctrl,
663e81a9076SMaciej S. Szmigiero 				1, 4, CX25840_VCONFIG_HRESETW_PIXCLK);
664e81a9076SMaciej S. Szmigiero 
665e81a9076SMaciej S. Szmigiero 	if (state->vid_config & CX25840_VCONFIG_CLKGATE_MASK)
666e81a9076SMaciej S. Szmigiero 		voutctrl[1] &= ~(3 << 6);
667e81a9076SMaciej S. Szmigiero 	switch (state->vid_config & CX25840_VCONFIG_CLKGATE_MASK) {
668e81a9076SMaciej S. Szmigiero 	case CX25840_VCONFIG_CLKGATE_VALID:
669e81a9076SMaciej S. Szmigiero 		voutctrl[1] |= 2;
670e81a9076SMaciej S. Szmigiero 		break;
671e81a9076SMaciej S. Szmigiero 
672e81a9076SMaciej S. Szmigiero 	case CX25840_VCONFIG_CLKGATE_VALIDACTIVE:
673e81a9076SMaciej S. Szmigiero 		voutctrl[1] |= 3;
674e81a9076SMaciej S. Szmigiero 		break;
675e81a9076SMaciej S. Szmigiero 
676e81a9076SMaciej S. Szmigiero 	case CX25840_VCONFIG_CLKGATE_NONE:
677e81a9076SMaciej S. Szmigiero 		/* zero */
678e81a9076SMaciej S. Szmigiero 	default:
679e81a9076SMaciej S. Szmigiero 		break;
680e81a9076SMaciej S. Szmigiero 	}
681e81a9076SMaciej S. Szmigiero 
682e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_DCMODE_MASK, voutctrl,
683e81a9076SMaciej S. Szmigiero 				2, 0, CX25840_VCONFIG_DCMODE_BYTES);
684e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_IDID0S_MASK, voutctrl,
685e81a9076SMaciej S. Szmigiero 				2, 1, CX25840_VCONFIG_IDID0S_LINECNT);
686e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VIPCLAMP_MASK, voutctrl,
687e81a9076SMaciej S. Szmigiero 				2, 4, CX25840_VCONFIG_VIPCLAMP_ENABLED);
688e81a9076SMaciej S. Szmigiero 
689e81a9076SMaciej S. Szmigiero 	for (i = 0; i < 3; i++)
690e81a9076SMaciej S. Szmigiero 		cx25840_write(client, 0x404 + i, voutctrl[i]);
691e81a9076SMaciej S. Szmigiero }
692e81a9076SMaciej S. Szmigiero 
cx25840_initialize(struct i2c_client * client)693cb7a01acSMauro Carvalho Chehab static void cx25840_initialize(struct i2c_client *client)
694cb7a01acSMauro Carvalho Chehab {
695cb7a01acSMauro Carvalho Chehab 	DEFINE_WAIT(wait);
696cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
697cb7a01acSMauro Carvalho Chehab 	struct workqueue_struct *q;
698cb7a01acSMauro Carvalho Chehab 
699cb7a01acSMauro Carvalho Chehab 	/* datasheet startup in numbered steps, refer to page 3-77 */
700cb7a01acSMauro Carvalho Chehab 	/* 2. */
701cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x803, ~0x10, 0x00);
70210a34367SMauro Carvalho Chehab 	/*
70310a34367SMauro Carvalho Chehab 	 * The default of this register should be 4, but I get 0 instead.
70410a34367SMauro Carvalho Chehab 	 * Set this register to 4 manually.
70510a34367SMauro Carvalho Chehab 	 */
706cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x000, 0x04);
707cb7a01acSMauro Carvalho Chehab 	/* 3. */
708cb7a01acSMauro Carvalho Chehab 	init_dll1(client);
709cb7a01acSMauro Carvalho Chehab 	init_dll2(client);
710cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x136, 0x0a);
711cb7a01acSMauro Carvalho Chehab 	/* 4. */
712cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x13c, 0x01);
713cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x13c, 0x00);
714cb7a01acSMauro Carvalho Chehab 	/* 5. */
71510a34367SMauro Carvalho Chehab 	/*
71610a34367SMauro Carvalho Chehab 	 * Do the firmware load in a work handler to prevent.
71710a34367SMauro Carvalho Chehab 	 * Otherwise the kernel is blocked waiting for the
71810a34367SMauro Carvalho Chehab 	 * bit-banging i2c interface to finish uploading the
71910a34367SMauro Carvalho Chehab 	 * firmware.
72010a34367SMauro Carvalho Chehab 	 */
721cb7a01acSMauro Carvalho Chehab 	INIT_WORK(&state->fw_work, cx25840_work_handler);
722cb7a01acSMauro Carvalho Chehab 	init_waitqueue_head(&state->fw_wait);
723cb7a01acSMauro Carvalho Chehab 	q = create_singlethread_workqueue("cx25840_fw");
72435378ce1SPan Bian 	if (q) {
725cb7a01acSMauro Carvalho Chehab 		prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
726cb7a01acSMauro Carvalho Chehab 		queue_work(q, &state->fw_work);
727cb7a01acSMauro Carvalho Chehab 		schedule();
728cb7a01acSMauro Carvalho Chehab 		finish_wait(&state->fw_wait, &wait);
729cb7a01acSMauro Carvalho Chehab 		destroy_workqueue(q);
73035378ce1SPan Bian 	}
731cb7a01acSMauro Carvalho Chehab 
732cb7a01acSMauro Carvalho Chehab 	/* 6. */
733cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x115, 0x8c);
734cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x116, 0x07);
735cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x118, 0x02);
736cb7a01acSMauro Carvalho Chehab 	/* 7. */
737cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x4a5, 0x80);
738cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x4a5, 0x00);
739cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x402, 0x00);
740cb7a01acSMauro Carvalho Chehab 	/* 8. */
741cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x401, ~0x18, 0);
742cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x4a2, ~0x10, 0x10);
743cb7a01acSMauro Carvalho Chehab 	/* steps 8c and 8d are done in change_input() */
744cb7a01acSMauro Carvalho Chehab 	/* 10. */
745cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x8d3, 0x1f);
746cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x8e3, 0x03);
747cb7a01acSMauro Carvalho Chehab 
748cb7a01acSMauro Carvalho Chehab 	cx25840_std_setup(client);
749cb7a01acSMauro Carvalho Chehab 
750cb7a01acSMauro Carvalho Chehab 	/* trial and error says these are needed to get audio */
751cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x914, 0xa0);
752cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x918, 0xa0);
753cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x919, 0x01);
754cb7a01acSMauro Carvalho Chehab 
755cb7a01acSMauro Carvalho Chehab 	/* stereo preferred */
756cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x809, 0x04);
757cb7a01acSMauro Carvalho Chehab 	/* AC97 shift */
758cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x8cf, 0x0f);
759cb7a01acSMauro Carvalho Chehab 
760cb7a01acSMauro Carvalho Chehab 	/* (re)set input */
761cb7a01acSMauro Carvalho Chehab 	set_input(client, state->vid_input, state->aud_input);
762cb7a01acSMauro Carvalho Chehab 
763e81a9076SMaciej S. Szmigiero 	if (state->generic_mode)
764e81a9076SMaciej S. Szmigiero 		cx25840_vconfig_apply(client);
765e81a9076SMaciej S. Szmigiero 
766cb7a01acSMauro Carvalho Chehab 	/* start microcontroller */
767cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x803, ~0x10, 0x10);
768cb7a01acSMauro Carvalho Chehab }
769cb7a01acSMauro Carvalho Chehab 
cx23885_initialize(struct i2c_client * client)770cb7a01acSMauro Carvalho Chehab static void cx23885_initialize(struct i2c_client *client)
771cb7a01acSMauro Carvalho Chehab {
772cb7a01acSMauro Carvalho Chehab 	DEFINE_WAIT(wait);
773cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
7743ee9bc12SBrad Love 	u32 clk_freq = 0;
775cb7a01acSMauro Carvalho Chehab 	struct workqueue_struct *q;
776cb7a01acSMauro Carvalho Chehab 
7773ee9bc12SBrad Love 	/* cx23885 sets hostdata to clk_freq pointer */
7783ee9bc12SBrad Love 	if (v4l2_get_subdev_hostdata(&state->sd))
7793ee9bc12SBrad Love 		clk_freq = *((u32 *)v4l2_get_subdev_hostdata(&state->sd));
7803ee9bc12SBrad Love 
781cb7a01acSMauro Carvalho Chehab 	/*
782cb7a01acSMauro Carvalho Chehab 	 * Come out of digital power down
783cb7a01acSMauro Carvalho Chehab 	 * The CX23888, at least, needs this, otherwise registers aside from
784cb7a01acSMauro Carvalho Chehab 	 * 0x0-0x2 can't be read or written.
785cb7a01acSMauro Carvalho Chehab 	 */
786cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x000, 0);
787cb7a01acSMauro Carvalho Chehab 
788cb7a01acSMauro Carvalho Chehab 	/* Internal Reset */
789cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x102, ~0x01, 0x01);
790cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x102, ~0x01, 0x00);
791cb7a01acSMauro Carvalho Chehab 
792cb7a01acSMauro Carvalho Chehab 	/* Stop microcontroller */
793cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x803, ~0x10, 0x00);
794cb7a01acSMauro Carvalho Chehab 
795cb7a01acSMauro Carvalho Chehab 	/* DIF in reset? */
796cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x398, 0);
797cb7a01acSMauro Carvalho Chehab 
798cb7a01acSMauro Carvalho Chehab 	/*
799cb7a01acSMauro Carvalho Chehab 	 * Trust the default xtal, no division
800cb7a01acSMauro Carvalho Chehab 	 * '885: 28.636363... MHz
801cb7a01acSMauro Carvalho Chehab 	 * '887: 25.000000 MHz
802cb7a01acSMauro Carvalho Chehab 	 * '888: 50.000000 MHz
803cb7a01acSMauro Carvalho Chehab 	 */
804cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x2, 0x76);
805cb7a01acSMauro Carvalho Chehab 
806cb7a01acSMauro Carvalho Chehab 	/* Power up all the PLL's and DLL */
807cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x1, 0x40);
808cb7a01acSMauro Carvalho Chehab 
809cb7a01acSMauro Carvalho Chehab 	/* Sys PLL */
810cb7a01acSMauro Carvalho Chehab 	switch (state->id) {
81129d6a98bSHans Verkuil 	case CX23888_AV:
812cb7a01acSMauro Carvalho Chehab 		/*
813cb7a01acSMauro Carvalho Chehab 		 * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz
814cb7a01acSMauro Carvalho Chehab 		 * 572.73 MHz before post divide
815cb7a01acSMauro Carvalho Chehab 		 */
8163ee9bc12SBrad Love 		if (clk_freq == 25000000) {
8173ee9bc12SBrad Love 			/* 888/ImpactVCBe or 25Mhz xtal */
8183ee9bc12SBrad Love 			; /* nothing to do */
8193ee9bc12SBrad Love 		} else {
820cb7a01acSMauro Carvalho Chehab 			/* HVR1850 or 50MHz xtal */
821cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x2, 0x71);
8223ee9bc12SBrad Love 		}
823cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x11c, 0x01d1744c);
824cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x118, 0x00000416);
825cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x404, 0x0010253e);
826cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x42c, 0x42600000);
827cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x44c, 0x161f1000);
828cb7a01acSMauro Carvalho Chehab 		break;
82929d6a98bSHans Verkuil 	case CX23887_AV:
830cb7a01acSMauro Carvalho Chehab 		/*
831cb7a01acSMauro Carvalho Chehab 		 * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz
832cb7a01acSMauro Carvalho Chehab 		 * 572.73 MHz before post divide
833cb7a01acSMauro Carvalho Chehab 		 */
834cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x11c, 0x01d1744c);
835cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x118, 0x00000416);
836cb7a01acSMauro Carvalho Chehab 		break;
83729d6a98bSHans Verkuil 	case CX23885_AV:
838cb7a01acSMauro Carvalho Chehab 	default:
839cb7a01acSMauro Carvalho Chehab 		/*
840cb7a01acSMauro Carvalho Chehab 		 * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz
841cb7a01acSMauro Carvalho Chehab 		 * 572.73 MHz before post divide
842cb7a01acSMauro Carvalho Chehab 		 */
843cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x11c, 0x00000000);
844cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x118, 0x00000414);
845cb7a01acSMauro Carvalho Chehab 		break;
846cb7a01acSMauro Carvalho Chehab 	}
847cb7a01acSMauro Carvalho Chehab 
848cb7a01acSMauro Carvalho Chehab 	/* Disable DIF bypass */
849cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x33c, 0x00000001);
850cb7a01acSMauro Carvalho Chehab 
851cb7a01acSMauro Carvalho Chehab 	/* DIF Src phase inc */
852cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x340, 0x0df7df83);
853cb7a01acSMauro Carvalho Chehab 
854cb7a01acSMauro Carvalho Chehab 	/*
855cb7a01acSMauro Carvalho Chehab 	 * Vid PLL
856cb7a01acSMauro Carvalho Chehab 	 * Setup for a BT.656 pixel clock of 13.5 Mpixels/second
857cb7a01acSMauro Carvalho Chehab 	 *
858cb7a01acSMauro Carvalho Chehab 	 * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz
859cb7a01acSMauro Carvalho Chehab 	 * 432.0 MHz before post divide
860cb7a01acSMauro Carvalho Chehab 	 */
861cb7a01acSMauro Carvalho Chehab 
862cb7a01acSMauro Carvalho Chehab 	/* HVR1850 */
863cb7a01acSMauro Carvalho Chehab 	switch (state->id) {
86429d6a98bSHans Verkuil 	case CX23888_AV:
8653ee9bc12SBrad Love 		if (clk_freq == 25000000) {
8663ee9bc12SBrad Love 			/* 888/ImpactVCBe or 25MHz xtal */
8673ee9bc12SBrad Love 			cx25840_write4(client, 0x10c, 0x01b6db7b);
8683ee9bc12SBrad Love 			cx25840_write4(client, 0x108, 0x00000512);
8693ee9bc12SBrad Love 		} else {
8703ee9bc12SBrad Love 			/* 888/HVR1250 or 50MHz xtal */
871cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x10c, 0x13333333);
872cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x108, 0x00000515);
8733ee9bc12SBrad Love 		}
874cb7a01acSMauro Carvalho Chehab 		break;
875cb7a01acSMauro Carvalho Chehab 	default:
876cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x10c, 0x002be2c9);
877cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x108, 0x0000040f);
878cb7a01acSMauro Carvalho Chehab 	}
879cb7a01acSMauro Carvalho Chehab 
880cb7a01acSMauro Carvalho Chehab 	/* Luma */
881cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x414, 0x00107d12);
882cb7a01acSMauro Carvalho Chehab 
883cb7a01acSMauro Carvalho Chehab 	/* Chroma */
884ee61cd9fSHans Verkuil 	if (is_cx23888(state))
885ee61cd9fSHans Verkuil 		cx25840_write4(client, 0x418, 0x1d008282);
886ee61cd9fSHans Verkuil 	else
887cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x420, 0x3d008282);
888cb7a01acSMauro Carvalho Chehab 
889cb7a01acSMauro Carvalho Chehab 	/*
890cb7a01acSMauro Carvalho Chehab 	 * Aux PLL
891cb7a01acSMauro Carvalho Chehab 	 * Initial setup for audio sample clock:
892cb7a01acSMauro Carvalho Chehab 	 * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz
893cb7a01acSMauro Carvalho Chehab 	 * Initial I2S output/master clock(?):
894cb7a01acSMauro Carvalho Chehab 	 * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz
895cb7a01acSMauro Carvalho Chehab 	 */
896cb7a01acSMauro Carvalho Chehab 	switch (state->id) {
89729d6a98bSHans Verkuil 	case CX23888_AV:
898cb7a01acSMauro Carvalho Chehab 		/*
899cb7a01acSMauro Carvalho Chehab 		 * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz
900cb7a01acSMauro Carvalho Chehab 		 * 368.64 MHz before post divide
901cb7a01acSMauro Carvalho Chehab 		 * 122.88 MHz / 0xa = 12.288 MHz
902cb7a01acSMauro Carvalho Chehab 		 */
9033ee9bc12SBrad Love 		/* HVR1850 or 50MHz xtal or 25MHz xtal */
904cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x114, 0x017dbf48);
905cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x110, 0x000a030e);
906cb7a01acSMauro Carvalho Chehab 		break;
90729d6a98bSHans Verkuil 	case CX23887_AV:
908cb7a01acSMauro Carvalho Chehab 		/*
909cb7a01acSMauro Carvalho Chehab 		 * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz
910cb7a01acSMauro Carvalho Chehab 		 * 368.64 MHz before post divide
911cb7a01acSMauro Carvalho Chehab 		 * 122.88 MHz / 0xa = 12.288 MHz
912cb7a01acSMauro Carvalho Chehab 		 */
913cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x114, 0x017dbf48);
914cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x110, 0x000a030e);
915cb7a01acSMauro Carvalho Chehab 		break;
91629d6a98bSHans Verkuil 	case CX23885_AV:
917cb7a01acSMauro Carvalho Chehab 	default:
918cb7a01acSMauro Carvalho Chehab 		/*
919cb7a01acSMauro Carvalho Chehab 		 * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz
920cb7a01acSMauro Carvalho Chehab 		 * 368.64 MHz before post divide
921cb7a01acSMauro Carvalho Chehab 		 * 122.88 MHz / 0xa = 12.288 MHz
922cb7a01acSMauro Carvalho Chehab 		 */
923cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x114, 0x01bf0c9e);
924cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x110, 0x000a030c);
925cb7a01acSMauro Carvalho Chehab 		break;
926c2c1b415SPeter Senna Tschudin 	}
927cb7a01acSMauro Carvalho Chehab 
928cb7a01acSMauro Carvalho Chehab 	/* ADC2 input select */
929cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x102, 0x10);
930cb7a01acSMauro Carvalho Chehab 
931cb7a01acSMauro Carvalho Chehab 	/* VIN1 & VIN5 */
932cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x103, 0x11);
933cb7a01acSMauro Carvalho Chehab 
934cb7a01acSMauro Carvalho Chehab 	/* Enable format auto detect */
935cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x400, 0);
936cb7a01acSMauro Carvalho Chehab 	/* Fast subchroma lock */
937cb7a01acSMauro Carvalho Chehab 	/* White crush, Chroma AGC & Chroma Killer enabled */
938cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x401, 0xe8);
939cb7a01acSMauro Carvalho Chehab 
940cb7a01acSMauro Carvalho Chehab 	/* Select AFE clock pad output source */
941cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x144, 0x05);
942cb7a01acSMauro Carvalho Chehab 
943cb7a01acSMauro Carvalho Chehab 	/* Drive GPIO2 direction and values for HVR1700
944cb7a01acSMauro Carvalho Chehab 	 * where an onboard mux selects the output of demodulator
945cb7a01acSMauro Carvalho Chehab 	 * vs the 417. Failure to set this results in no DTV.
946cb7a01acSMauro Carvalho Chehab 	 * It's safe to set this across all Hauppauge boards
947cb7a01acSMauro Carvalho Chehab 	 * currently, regardless of the board type.
948cb7a01acSMauro Carvalho Chehab 	 */
949cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x160, 0x1d);
950cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x164, 0x00);
951cb7a01acSMauro Carvalho Chehab 
95210a34367SMauro Carvalho Chehab 	/*
95310a34367SMauro Carvalho Chehab 	 * Do the firmware load in a work handler to prevent.
95410a34367SMauro Carvalho Chehab 	 * Otherwise the kernel is blocked waiting for the
95510a34367SMauro Carvalho Chehab 	 * bit-banging i2c interface to finish uploading the
95610a34367SMauro Carvalho Chehab 	 * firmware.
95710a34367SMauro Carvalho Chehab 	 */
958cb7a01acSMauro Carvalho Chehab 	INIT_WORK(&state->fw_work, cx25840_work_handler);
959cb7a01acSMauro Carvalho Chehab 	init_waitqueue_head(&state->fw_wait);
960cb7a01acSMauro Carvalho Chehab 	q = create_singlethread_workqueue("cx25840_fw");
96135378ce1SPan Bian 	if (q) {
962cb7a01acSMauro Carvalho Chehab 		prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
963cb7a01acSMauro Carvalho Chehab 		queue_work(q, &state->fw_work);
964cb7a01acSMauro Carvalho Chehab 		schedule();
965cb7a01acSMauro Carvalho Chehab 		finish_wait(&state->fw_wait, &wait);
966cb7a01acSMauro Carvalho Chehab 		destroy_workqueue(q);
96735378ce1SPan Bian 	}
968cb7a01acSMauro Carvalho Chehab 
96910a34367SMauro Carvalho Chehab 	/*
97010a34367SMauro Carvalho Chehab 	 * Call the cx23888 specific std setup func, we no longer rely on
971cb7a01acSMauro Carvalho Chehab 	 * the generic cx24840 func.
972cb7a01acSMauro Carvalho Chehab 	 */
973cb7a01acSMauro Carvalho Chehab 	if (is_cx23888(state))
974cb7a01acSMauro Carvalho Chehab 		cx23888_std_setup(client);
975cb7a01acSMauro Carvalho Chehab 	else
976cb7a01acSMauro Carvalho Chehab 		cx25840_std_setup(client);
977cb7a01acSMauro Carvalho Chehab 
978cb7a01acSMauro Carvalho Chehab 	/* (re)set input */
979cb7a01acSMauro Carvalho Chehab 	set_input(client, state->vid_input, state->aud_input);
980cb7a01acSMauro Carvalho Chehab 
981cb7a01acSMauro Carvalho Chehab 	/* start microcontroller */
982cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x803, ~0x10, 0x10);
983cb7a01acSMauro Carvalho Chehab 
984cb7a01acSMauro Carvalho Chehab 	/* Disable and clear video interrupts - we don't use them */
985cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0xffffffff);
986cb7a01acSMauro Carvalho Chehab 
987cb7a01acSMauro Carvalho Chehab 	/* Disable and clear audio interrupts - we don't use them */
988cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff);
989cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff);
990cb7a01acSMauro Carvalho Chehab 
991cb7a01acSMauro Carvalho Chehab 	/* CC raw enable */
99210a34367SMauro Carvalho Chehab 
99310a34367SMauro Carvalho Chehab 	/*
99410a34367SMauro Carvalho Chehab 	 *  - VIP 1.1 control codes - 10bit, blue field enable.
995cb7a01acSMauro Carvalho Chehab 	 *  - enable raw data during vertical blanking.
996cb7a01acSMauro Carvalho Chehab 	 *  - enable ancillary Data insertion for 656 or VIP.
997cb7a01acSMauro Carvalho Chehab 	 */
998cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x404, 0x0010253e);
999cb7a01acSMauro Carvalho Chehab 
1000038fd414SBrad Love 	/* CC on  - VBI_LINE_CTRL3, FLD_VBI_MD_LINE12 */
1001cdf472d3SHans Verkuil 	cx25840_write(client, state->vbi_regs_offset + 0x42f, 0x66);
1002cb7a01acSMauro Carvalho Chehab 
1003cb7a01acSMauro Carvalho Chehab 	/* HVR-1250 / HVR1850 DIF related */
1004cb7a01acSMauro Carvalho Chehab 	/* Power everything up */
1005cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x130, 0x0);
1006cb7a01acSMauro Carvalho Chehab 
1007038fd414SBrad Love 	/* SRC_COMB_CFG */
1008ee61cd9fSHans Verkuil 	if (is_cx23888(state))
1009ee61cd9fSHans Verkuil 		cx25840_write4(client, 0x454, 0x6628021F);
1010ee61cd9fSHans Verkuil 	else
1011cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x478, 0x6628021F);
1012cb7a01acSMauro Carvalho Chehab 
1013cb7a01acSMauro Carvalho Chehab 	/* AFE_CLK_OUT_CTRL - Select the clock output source as output */
1014cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x144, 0x5);
1015cb7a01acSMauro Carvalho Chehab 
1016cb7a01acSMauro Carvalho Chehab 	/* I2C_OUT_CTL - I2S output configuration as
1017cb7a01acSMauro Carvalho Chehab 	 * Master, Sony, Left justified, left sample on WS=1
1018cb7a01acSMauro Carvalho Chehab 	 */
1019cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x918, 0x1a0);
1020cb7a01acSMauro Carvalho Chehab 
1021cb7a01acSMauro Carvalho Chehab 	/* AFE_DIAG_CTRL1 */
1022cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x134, 0x000a1800);
1023cb7a01acSMauro Carvalho Chehab 
1024cb7a01acSMauro Carvalho Chehab 	/* AFE_DIAG_CTRL3 - Inverted Polarity for Audio and Video */
1025cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x13c, 0x00310000);
1026cb7a01acSMauro Carvalho Chehab }
1027cb7a01acSMauro Carvalho Chehab 
1028cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1029cb7a01acSMauro Carvalho Chehab 
cx231xx_initialize(struct i2c_client * client)1030cb7a01acSMauro Carvalho Chehab static void cx231xx_initialize(struct i2c_client *client)
1031cb7a01acSMauro Carvalho Chehab {
1032cb7a01acSMauro Carvalho Chehab 	DEFINE_WAIT(wait);
1033cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
1034cb7a01acSMauro Carvalho Chehab 	struct workqueue_struct *q;
1035cb7a01acSMauro Carvalho Chehab 
1036cb7a01acSMauro Carvalho Chehab 	/* Internal Reset */
1037cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x102, ~0x01, 0x01);
1038cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x102, ~0x01, 0x00);
1039cb7a01acSMauro Carvalho Chehab 
1040cb7a01acSMauro Carvalho Chehab 	/* Stop microcontroller */
1041cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x803, ~0x10, 0x00);
1042cb7a01acSMauro Carvalho Chehab 
1043cb7a01acSMauro Carvalho Chehab 	/* DIF in reset? */
1044cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x398, 0);
1045cb7a01acSMauro Carvalho Chehab 
1046cb7a01acSMauro Carvalho Chehab 	/* Trust the default xtal, no division */
1047cb7a01acSMauro Carvalho Chehab 	/* This changes for the cx23888 products */
1048cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x2, 0x76);
1049cb7a01acSMauro Carvalho Chehab 
1050cb7a01acSMauro Carvalho Chehab 	/* Bring down the regulator for AUX clk */
1051cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x1, 0x40);
1052cb7a01acSMauro Carvalho Chehab 
1053cb7a01acSMauro Carvalho Chehab 	/* Disable DIF bypass */
1054cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x33c, 0x00000001);
1055cb7a01acSMauro Carvalho Chehab 
1056cb7a01acSMauro Carvalho Chehab 	/* DIF Src phase inc */
1057cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x340, 0x0df7df83);
1058cb7a01acSMauro Carvalho Chehab 
1059cb7a01acSMauro Carvalho Chehab 	/* Luma */
1060cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x414, 0x00107d12);
1061cb7a01acSMauro Carvalho Chehab 
1062cb7a01acSMauro Carvalho Chehab 	/* Chroma */
1063cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x420, 0x3d008282);
1064cb7a01acSMauro Carvalho Chehab 
1065cb7a01acSMauro Carvalho Chehab 	/* ADC2 input select */
1066cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x102, 0x10);
1067cb7a01acSMauro Carvalho Chehab 
1068cb7a01acSMauro Carvalho Chehab 	/* VIN1 & VIN5 */
1069cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x103, 0x11);
1070cb7a01acSMauro Carvalho Chehab 
1071cb7a01acSMauro Carvalho Chehab 	/* Enable format auto detect */
1072cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x400, 0);
1073cb7a01acSMauro Carvalho Chehab 	/* Fast subchroma lock */
1074cb7a01acSMauro Carvalho Chehab 	/* White crush, Chroma AGC & Chroma Killer enabled */
1075cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x401, 0xe8);
1076cb7a01acSMauro Carvalho Chehab 
107710a34367SMauro Carvalho Chehab 	/*
107810a34367SMauro Carvalho Chehab 	 * Do the firmware load in a work handler to prevent.
107910a34367SMauro Carvalho Chehab 	 * Otherwise the kernel is blocked waiting for the
108010a34367SMauro Carvalho Chehab 	 * bit-banging i2c interface to finish uploading the
108110a34367SMauro Carvalho Chehab 	 * firmware.
108210a34367SMauro Carvalho Chehab 	 */
1083cb7a01acSMauro Carvalho Chehab 	INIT_WORK(&state->fw_work, cx25840_work_handler);
1084cb7a01acSMauro Carvalho Chehab 	init_waitqueue_head(&state->fw_wait);
1085cb7a01acSMauro Carvalho Chehab 	q = create_singlethread_workqueue("cx25840_fw");
108635378ce1SPan Bian 	if (q) {
1087cb7a01acSMauro Carvalho Chehab 		prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
1088cb7a01acSMauro Carvalho Chehab 		queue_work(q, &state->fw_work);
1089cb7a01acSMauro Carvalho Chehab 		schedule();
1090cb7a01acSMauro Carvalho Chehab 		finish_wait(&state->fw_wait, &wait);
1091cb7a01acSMauro Carvalho Chehab 		destroy_workqueue(q);
109235378ce1SPan Bian 	}
1093cb7a01acSMauro Carvalho Chehab 
1094cb7a01acSMauro Carvalho Chehab 	cx25840_std_setup(client);
1095cb7a01acSMauro Carvalho Chehab 
1096cb7a01acSMauro Carvalho Chehab 	/* (re)set input */
1097cb7a01acSMauro Carvalho Chehab 	set_input(client, state->vid_input, state->aud_input);
1098cb7a01acSMauro Carvalho Chehab 
1099cb7a01acSMauro Carvalho Chehab 	/* start microcontroller */
1100cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x803, ~0x10, 0x10);
1101cb7a01acSMauro Carvalho Chehab 
1102cb7a01acSMauro Carvalho Chehab 	/* CC raw enable */
1103cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x404, 0x0b);
1104cb7a01acSMauro Carvalho Chehab 
1105cb7a01acSMauro Carvalho Chehab 	/* CC on */
1106cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x42f, 0x66);
1107cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x474, 0x1e1e601a);
1108cb7a01acSMauro Carvalho Chehab }
1109cb7a01acSMauro Carvalho Chehab 
1110cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1111cb7a01acSMauro Carvalho Chehab 
cx25840_std_setup(struct i2c_client * client)1112cb7a01acSMauro Carvalho Chehab void cx25840_std_setup(struct i2c_client *client)
1113cb7a01acSMauro Carvalho Chehab {
1114cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
1115cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std = state->std;
1116cb7a01acSMauro Carvalho Chehab 	int hblank, hactive, burst, vblank, vactive, sc;
1117cb7a01acSMauro Carvalho Chehab 	int vblank656, src_decimation;
1118cb7a01acSMauro Carvalho Chehab 	int luma_lpf, uv_lpf, comb;
1119cb7a01acSMauro Carvalho Chehab 	u32 pll_int, pll_frac, pll_post;
1120cb7a01acSMauro Carvalho Chehab 
1121cb7a01acSMauro Carvalho Chehab 	/* datasheet startup, step 8d */
1122cb7a01acSMauro Carvalho Chehab 	if (std & ~V4L2_STD_NTSC)
1123cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x49f, 0x11);
1124cb7a01acSMauro Carvalho Chehab 	else
1125cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x49f, 0x14);
1126cb7a01acSMauro Carvalho Chehab 
1127e81a9076SMaciej S. Szmigiero 	/* generic mode uses the values that the chip autoconfig would set */
1128cb7a01acSMauro Carvalho Chehab 	if (std & V4L2_STD_625_50) {
1129cb7a01acSMauro Carvalho Chehab 		hblank = 132;
1130cb7a01acSMauro Carvalho Chehab 		hactive = 720;
1131cb7a01acSMauro Carvalho Chehab 		burst = 93;
1132e81a9076SMaciej S. Szmigiero 		if (state->generic_mode) {
1133e81a9076SMaciej S. Szmigiero 			vblank = 34;
1134e81a9076SMaciej S. Szmigiero 			vactive = 576;
1135e81a9076SMaciej S. Szmigiero 			vblank656 = 38;
1136e81a9076SMaciej S. Szmigiero 		} else {
1137cb7a01acSMauro Carvalho Chehab 			vblank = 36;
1138cb7a01acSMauro Carvalho Chehab 			vactive = 580;
1139cb7a01acSMauro Carvalho Chehab 			vblank656 = 40;
1140e81a9076SMaciej S. Szmigiero 		}
1141cb7a01acSMauro Carvalho Chehab 		src_decimation = 0x21f;
1142cb7a01acSMauro Carvalho Chehab 		luma_lpf = 2;
1143cb7a01acSMauro Carvalho Chehab 
1144cb7a01acSMauro Carvalho Chehab 		if (std & V4L2_STD_SECAM) {
1145cb7a01acSMauro Carvalho Chehab 			uv_lpf = 0;
1146cb7a01acSMauro Carvalho Chehab 			comb = 0;
1147cb7a01acSMauro Carvalho Chehab 			sc = 0x0a425f;
1148cb7a01acSMauro Carvalho Chehab 		} else if (std == V4L2_STD_PAL_Nc) {
1149e81a9076SMaciej S. Szmigiero 			if (state->generic_mode) {
1150e81a9076SMaciej S. Szmigiero 				burst = 95;
1151e81a9076SMaciej S. Szmigiero 				luma_lpf = 1;
1152e81a9076SMaciej S. Szmigiero 			}
1153cb7a01acSMauro Carvalho Chehab 			uv_lpf = 1;
1154cb7a01acSMauro Carvalho Chehab 			comb = 0x20;
1155cb7a01acSMauro Carvalho Chehab 			sc = 556453;
1156cb7a01acSMauro Carvalho Chehab 		} else {
1157cb7a01acSMauro Carvalho Chehab 			uv_lpf = 1;
1158cb7a01acSMauro Carvalho Chehab 			comb = 0x20;
1159cb7a01acSMauro Carvalho Chehab 			sc = 688739;
1160cb7a01acSMauro Carvalho Chehab 		}
1161cb7a01acSMauro Carvalho Chehab 	} else {
1162cb7a01acSMauro Carvalho Chehab 		hactive = 720;
1163cb7a01acSMauro Carvalho Chehab 		hblank = 122;
1164cb7a01acSMauro Carvalho Chehab 		vactive = 487;
1165cb7a01acSMauro Carvalho Chehab 		luma_lpf = 1;
1166cb7a01acSMauro Carvalho Chehab 		uv_lpf = 1;
1167e81a9076SMaciej S. Szmigiero 		if (state->generic_mode) {
1168e81a9076SMaciej S. Szmigiero 			vblank = 20;
1169e81a9076SMaciej S. Szmigiero 			vblank656 = 24;
1170e81a9076SMaciej S. Szmigiero 		}
1171cb7a01acSMauro Carvalho Chehab 
1172cb7a01acSMauro Carvalho Chehab 		src_decimation = 0x21f;
1173cb7a01acSMauro Carvalho Chehab 		if (std == V4L2_STD_PAL_60) {
1174e81a9076SMaciej S. Szmigiero 			if (!state->generic_mode) {
1175cb7a01acSMauro Carvalho Chehab 				vblank = 26;
1176cb7a01acSMauro Carvalho Chehab 				vblank656 = 26;
1177cb7a01acSMauro Carvalho Chehab 				burst = 0x5b;
117810a34367SMauro Carvalho Chehab 			} else {
1179e81a9076SMaciej S. Szmigiero 				burst = 0x59;
118010a34367SMauro Carvalho Chehab 			}
1181cb7a01acSMauro Carvalho Chehab 			luma_lpf = 2;
1182cb7a01acSMauro Carvalho Chehab 			comb = 0x20;
1183cb7a01acSMauro Carvalho Chehab 			sc = 688739;
1184cb7a01acSMauro Carvalho Chehab 		} else if (std == V4L2_STD_PAL_M) {
1185cb7a01acSMauro Carvalho Chehab 			vblank = 20;
1186cb7a01acSMauro Carvalho Chehab 			vblank656 = 24;
1187cb7a01acSMauro Carvalho Chehab 			burst = 0x61;
1188cb7a01acSMauro Carvalho Chehab 			comb = 0x20;
1189cb7a01acSMauro Carvalho Chehab 			sc = 555452;
1190cb7a01acSMauro Carvalho Chehab 		} else {
1191e81a9076SMaciej S. Szmigiero 			if (!state->generic_mode) {
1192cb7a01acSMauro Carvalho Chehab 				vblank = 26;
1193cb7a01acSMauro Carvalho Chehab 				vblank656 = 26;
1194e81a9076SMaciej S. Szmigiero 			}
1195cb7a01acSMauro Carvalho Chehab 			burst = 0x5b;
1196cb7a01acSMauro Carvalho Chehab 			comb = 0x66;
1197cb7a01acSMauro Carvalho Chehab 			sc = 556063;
1198cb7a01acSMauro Carvalho Chehab 		}
1199cb7a01acSMauro Carvalho Chehab 	}
1200cb7a01acSMauro Carvalho Chehab 
1201cb7a01acSMauro Carvalho Chehab 	/* DEBUG: Displays configured PLL frequency */
1202cb7a01acSMauro Carvalho Chehab 	if (!is_cx231xx(state)) {
1203cb7a01acSMauro Carvalho Chehab 		pll_int = cx25840_read(client, 0x108);
1204cb7a01acSMauro Carvalho Chehab 		pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff;
1205cb7a01acSMauro Carvalho Chehab 		pll_post = cx25840_read(client, 0x109);
1206cb7a01acSMauro Carvalho Chehab 		v4l_dbg(1, cx25840_debug, client,
1207cb7a01acSMauro Carvalho Chehab 			"PLL regs = int: %u, frac: %u, post: %u\n",
1208cb7a01acSMauro Carvalho Chehab 			pll_int, pll_frac, pll_post);
1209cb7a01acSMauro Carvalho Chehab 
1210cb7a01acSMauro Carvalho Chehab 		if (pll_post) {
1211cb7a01acSMauro Carvalho Chehab 			int fin, fsc;
1212cb7a01acSMauro Carvalho Chehab 			int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L;
1213cb7a01acSMauro Carvalho Chehab 
1214cb7a01acSMauro Carvalho Chehab 			pll /= pll_post;
121510a34367SMauro Carvalho Chehab 			v4l_dbg(1, cx25840_debug, client,
121610a34367SMauro Carvalho Chehab 				"PLL = %d.%06d MHz\n",
1217cb7a01acSMauro Carvalho Chehab 				pll / 1000000, pll % 1000000);
121810a34367SMauro Carvalho Chehab 			v4l_dbg(1, cx25840_debug, client,
121910a34367SMauro Carvalho Chehab 				"PLL/8 = %d.%06d MHz\n",
1220cb7a01acSMauro Carvalho Chehab 				pll / 8000000, (pll / 8) % 1000000);
1221cb7a01acSMauro Carvalho Chehab 
1222cb7a01acSMauro Carvalho Chehab 			fin = ((u64)src_decimation * pll) >> 12;
1223cb7a01acSMauro Carvalho Chehab 			v4l_dbg(1, cx25840_debug, client,
1224cb7a01acSMauro Carvalho Chehab 				"ADC Sampling freq = %d.%06d MHz\n",
1225cb7a01acSMauro Carvalho Chehab 				fin / 1000000, fin % 1000000);
1226cb7a01acSMauro Carvalho Chehab 
1227cb7a01acSMauro Carvalho Chehab 			fsc = (((u64)sc) * pll) >> 24L;
1228cb7a01acSMauro Carvalho Chehab 			v4l_dbg(1, cx25840_debug, client,
1229cb7a01acSMauro Carvalho Chehab 				"Chroma sub-carrier freq = %d.%06d MHz\n",
1230cb7a01acSMauro Carvalho Chehab 				fsc / 1000000, fsc % 1000000);
1231cb7a01acSMauro Carvalho Chehab 
123210a34367SMauro Carvalho Chehab 			v4l_dbg(1, cx25840_debug, client,
123310a34367SMauro Carvalho Chehab 				"hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n",
1234cb7a01acSMauro Carvalho Chehab 				hblank, hactive, vblank, vactive, vblank656,
123510a34367SMauro Carvalho Chehab 				src_decimation, burst, luma_lpf, uv_lpf,
123610a34367SMauro Carvalho Chehab 				comb, sc);
1237cb7a01acSMauro Carvalho Chehab 		}
1238cb7a01acSMauro Carvalho Chehab 	}
1239cb7a01acSMauro Carvalho Chehab 
1240cb7a01acSMauro Carvalho Chehab 	/* Sets horizontal blanking delay and active lines */
1241cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x470, hblank);
1242cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x471,
124385273c38SJoe Perches 		      (((hblank >> 8) & 0x3) | (hactive << 4)) & 0xff);
1244cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x472, hactive >> 4);
1245cb7a01acSMauro Carvalho Chehab 
1246cb7a01acSMauro Carvalho Chehab 	/* Sets burst gate delay */
1247cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x473, burst);
1248cb7a01acSMauro Carvalho Chehab 
1249cb7a01acSMauro Carvalho Chehab 	/* Sets vertical blanking delay and active duration */
1250cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x474, vblank);
1251cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x475,
125285273c38SJoe Perches 		      (((vblank >> 8) & 0x3) | (vactive << 4)) & 0xff);
1253cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x476, vactive >> 4);
1254cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x477, vblank656);
1255cb7a01acSMauro Carvalho Chehab 
1256cb7a01acSMauro Carvalho Chehab 	/* Sets src decimation rate */
125785273c38SJoe Perches 	cx25840_write(client, 0x478, src_decimation & 0xff);
125885273c38SJoe Perches 	cx25840_write(client, 0x479, (src_decimation >> 8) & 0xff);
1259cb7a01acSMauro Carvalho Chehab 
1260cb7a01acSMauro Carvalho Chehab 	/* Sets Luma and UV Low pass filters */
1261cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
1262cb7a01acSMauro Carvalho Chehab 
1263cb7a01acSMauro Carvalho Chehab 	/* Enables comb filters */
1264cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x47b, comb);
1265cb7a01acSMauro Carvalho Chehab 
1266cb7a01acSMauro Carvalho Chehab 	/* Sets SC Step*/
1267cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x47c, sc);
126885273c38SJoe Perches 	cx25840_write(client, 0x47d, (sc >> 8) & 0xff);
126985273c38SJoe Perches 	cx25840_write(client, 0x47e, (sc >> 16) & 0xff);
1270cb7a01acSMauro Carvalho Chehab 
1271cb7a01acSMauro Carvalho Chehab 	/* Sets VBI parameters */
1272cb7a01acSMauro Carvalho Chehab 	if (std & V4L2_STD_625_50) {
1273cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x47f, 0x01);
1274cb7a01acSMauro Carvalho Chehab 		state->vbi_line_offset = 5;
1275cb7a01acSMauro Carvalho Chehab 	} else {
1276cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x47f, 0x00);
1277cb7a01acSMauro Carvalho Chehab 		state->vbi_line_offset = 8;
1278cb7a01acSMauro Carvalho Chehab 	}
1279cb7a01acSMauro Carvalho Chehab }
1280cb7a01acSMauro Carvalho Chehab 
1281cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1282cb7a01acSMauro Carvalho Chehab 
input_change(struct i2c_client * client)1283cb7a01acSMauro Carvalho Chehab static void input_change(struct i2c_client *client)
1284cb7a01acSMauro Carvalho Chehab {
1285cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
1286cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std = state->std;
1287cb7a01acSMauro Carvalho Chehab 
1288cb7a01acSMauro Carvalho Chehab 	/* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
1289cb7a01acSMauro Carvalho Chehab 	if (std & V4L2_STD_SECAM) {
1290cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x402, 0);
129110a34367SMauro Carvalho Chehab 	} else {
1292cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x402, 0x04);
129310a34367SMauro Carvalho Chehab 		cx25840_write(client, 0x49f,
129410a34367SMauro Carvalho Chehab 			      (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
1295cb7a01acSMauro Carvalho Chehab 	}
1296cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x401, ~0x60, 0);
1297cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x401, ~0x60, 0x60);
1298cb7a01acSMauro Carvalho Chehab 
1299cb7a01acSMauro Carvalho Chehab 	/* Don't write into audio registers on cx2583x chips */
1300cb7a01acSMauro Carvalho Chehab 	if (is_cx2583x(state))
1301cb7a01acSMauro Carvalho Chehab 		return;
1302cb7a01acSMauro Carvalho Chehab 
1303cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x810, ~0x01, 1);
1304cb7a01acSMauro Carvalho Chehab 
1305cb7a01acSMauro Carvalho Chehab 	if (state->radio) {
1306cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x808, 0xf9);
1307cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x80b, 0x00);
130810a34367SMauro Carvalho Chehab 	} else if (std & V4L2_STD_525_60) {
130910a34367SMauro Carvalho Chehab 		/*
131010a34367SMauro Carvalho Chehab 		 * Certain Hauppauge PVR150 models have a hardware bug
131110a34367SMauro Carvalho Chehab 		 * that causes audio to drop out. For these models the
131210a34367SMauro Carvalho Chehab 		 * audio standard must be set explicitly.
131310a34367SMauro Carvalho Chehab 		 * To be precise: it affects cards with tuner models
131410a34367SMauro Carvalho Chehab 		 * 85, 99 and 112 (model numbers from tveeprom).
131510a34367SMauro Carvalho Chehab 		 */
1316cb7a01acSMauro Carvalho Chehab 		int hw_fix = state->pvr150_workaround;
1317cb7a01acSMauro Carvalho Chehab 
1318cb7a01acSMauro Carvalho Chehab 		if (std == V4L2_STD_NTSC_M_JP) {
1319cb7a01acSMauro Carvalho Chehab 			/* Japan uses EIAJ audio standard */
1320cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7);
1321cb7a01acSMauro Carvalho Chehab 		} else if (std == V4L2_STD_NTSC_M_KR) {
1322cb7a01acSMauro Carvalho Chehab 			/* South Korea uses A2 audio standard */
1323cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8);
1324cb7a01acSMauro Carvalho Chehab 		} else {
1325cb7a01acSMauro Carvalho Chehab 			/* Others use the BTSC audio standard */
1326cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);
1327cb7a01acSMauro Carvalho Chehab 		}
1328cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x80b, 0x00);
1329cb7a01acSMauro Carvalho Chehab 	} else if (std & V4L2_STD_PAL) {
1330cb7a01acSMauro Carvalho Chehab 		/* Autodetect audio standard and audio system */
1331cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x808, 0xff);
133210a34367SMauro Carvalho Chehab 		/*
133310a34367SMauro Carvalho Chehab 		 * Since system PAL-L is pretty much non-existent and
133410a34367SMauro Carvalho Chehab 		 * not used by any public broadcast network, force
133510a34367SMauro Carvalho Chehab 		 * 6.5 MHz carrier to be interpreted as System DK,
133610a34367SMauro Carvalho Chehab 		 * this avoids DK audio detection instability
133710a34367SMauro Carvalho Chehab 		 */
1338cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x80b, 0x00);
1339cb7a01acSMauro Carvalho Chehab 	} else if (std & V4L2_STD_SECAM) {
1340cb7a01acSMauro Carvalho Chehab 		/* Autodetect audio standard and audio system */
1341cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x808, 0xff);
134210a34367SMauro Carvalho Chehab 		/*
134310a34367SMauro Carvalho Chehab 		 * If only one of SECAM-DK / SECAM-L is required, then force
134410a34367SMauro Carvalho Chehab 		 * 6.5MHz carrier, else autodetect it
134510a34367SMauro Carvalho Chehab 		 */
1346cb7a01acSMauro Carvalho Chehab 		if ((std & V4L2_STD_SECAM_DK) &&
1347cb7a01acSMauro Carvalho Chehab 		    !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
1348cb7a01acSMauro Carvalho Chehab 			/* 6.5 MHz carrier to be interpreted as System DK */
1349cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x80b, 0x00);
1350cb7a01acSMauro Carvalho Chehab 		} else if (!(std & V4L2_STD_SECAM_DK) &&
1351cb7a01acSMauro Carvalho Chehab 			   (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) {
1352cb7a01acSMauro Carvalho Chehab 			/* 6.5 MHz carrier to be interpreted as System L */
1353cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x80b, 0x08);
1354cb7a01acSMauro Carvalho Chehab 		} else {
1355cb7a01acSMauro Carvalho Chehab 			/* 6.5 MHz carrier to be autodetected */
1356cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x80b, 0x10);
1357cb7a01acSMauro Carvalho Chehab 		}
1358cb7a01acSMauro Carvalho Chehab 	}
1359cb7a01acSMauro Carvalho Chehab 
1360cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x810, ~0x01, 0);
1361cb7a01acSMauro Carvalho Chehab }
1362cb7a01acSMauro Carvalho Chehab 
set_input(struct i2c_client * client,enum cx25840_video_input vid_input,enum cx25840_audio_input aud_input)136310a34367SMauro Carvalho Chehab static int set_input(struct i2c_client *client,
136410a34367SMauro Carvalho Chehab 		     enum cx25840_video_input vid_input,
1365cb7a01acSMauro Carvalho Chehab 		     enum cx25840_audio_input aud_input)
1366cb7a01acSMauro Carvalho Chehab {
1367cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
1368cb7a01acSMauro Carvalho Chehab 	u8 is_composite = (vid_input >= CX25840_COMPOSITE1 &&
1369cb7a01acSMauro Carvalho Chehab 			   vid_input <= CX25840_COMPOSITE8);
1370cb7a01acSMauro Carvalho Chehab 	u8 is_component = (vid_input & CX25840_COMPONENT_ON) ==
1371cb7a01acSMauro Carvalho Chehab 			CX25840_COMPONENT_ON;
1372cb7a01acSMauro Carvalho Chehab 	u8 is_dif = (vid_input & CX25840_DIF_ON) ==
1373cb7a01acSMauro Carvalho Chehab 			CX25840_DIF_ON;
1374cb7a01acSMauro Carvalho Chehab 	u8 is_svideo = (vid_input & CX25840_SVIDEO_ON) ==
1375cb7a01acSMauro Carvalho Chehab 			CX25840_SVIDEO_ON;
1376cb7a01acSMauro Carvalho Chehab 	int luma = vid_input & 0xf0;
1377cb7a01acSMauro Carvalho Chehab 	int chroma = vid_input & 0xf00;
1378cb7a01acSMauro Carvalho Chehab 	u8 reg;
1379cb7a01acSMauro Carvalho Chehab 	u32 val;
1380cb7a01acSMauro Carvalho Chehab 
1381cb7a01acSMauro Carvalho Chehab 	v4l_dbg(1, cx25840_debug, client,
1382cb7a01acSMauro Carvalho Chehab 		"decoder set video input %d, audio input %d\n",
1383cb7a01acSMauro Carvalho Chehab 		vid_input, aud_input);
1384cb7a01acSMauro Carvalho Chehab 
1385cb7a01acSMauro Carvalho Chehab 	if (vid_input >= CX25840_VIN1_CH1) {
1386cb7a01acSMauro Carvalho Chehab 		v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n",
1387cb7a01acSMauro Carvalho Chehab 			vid_input);
1388cb7a01acSMauro Carvalho Chehab 		reg = vid_input & 0xff;
1389cb7a01acSMauro Carvalho Chehab 		is_composite = !is_component &&
1390cb7a01acSMauro Carvalho Chehab 			       ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON);
1391cb7a01acSMauro Carvalho Chehab 
1392cb7a01acSMauro Carvalho Chehab 		v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n",
1393cb7a01acSMauro Carvalho Chehab 			reg, is_composite);
1394cb7a01acSMauro Carvalho Chehab 	} else if (is_composite) {
1395cb7a01acSMauro Carvalho Chehab 		reg = 0xf0 + (vid_input - CX25840_COMPOSITE1);
1396cb7a01acSMauro Carvalho Chehab 	} else {
1397cb7a01acSMauro Carvalho Chehab 		if ((vid_input & ~0xff0) ||
139810a34367SMauro Carvalho Chehab 		    luma < CX25840_SVIDEO_LUMA1 ||
139910a34367SMauro Carvalho Chehab 		    luma > CX25840_SVIDEO_LUMA8 ||
140010a34367SMauro Carvalho Chehab 		    chroma < CX25840_SVIDEO_CHROMA4 ||
140110a34367SMauro Carvalho Chehab 		    chroma > CX25840_SVIDEO_CHROMA8) {
1402cb7a01acSMauro Carvalho Chehab 			v4l_err(client, "0x%04x is not a valid video input!\n",
1403cb7a01acSMauro Carvalho Chehab 				vid_input);
1404cb7a01acSMauro Carvalho Chehab 			return -EINVAL;
1405cb7a01acSMauro Carvalho Chehab 		}
1406cb7a01acSMauro Carvalho Chehab 		reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4);
1407cb7a01acSMauro Carvalho Chehab 		if (chroma >= CX25840_SVIDEO_CHROMA7) {
1408cb7a01acSMauro Carvalho Chehab 			reg &= 0x3f;
1409cb7a01acSMauro Carvalho Chehab 			reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2;
1410cb7a01acSMauro Carvalho Chehab 		} else {
1411cb7a01acSMauro Carvalho Chehab 			reg &= 0xcf;
1412cb7a01acSMauro Carvalho Chehab 			reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4;
1413cb7a01acSMauro Carvalho Chehab 		}
1414cb7a01acSMauro Carvalho Chehab 	}
1415cb7a01acSMauro Carvalho Chehab 
1416cb7a01acSMauro Carvalho Chehab 	/* The caller has previously prepared the correct routing
1417cb7a01acSMauro Carvalho Chehab 	 * configuration in reg (for the cx23885) so we have no
1418cb7a01acSMauro Carvalho Chehab 	 * need to attempt to flip bits for earlier av decoders.
1419cb7a01acSMauro Carvalho Chehab 	 */
1420cb7a01acSMauro Carvalho Chehab 	if (!is_cx2388x(state) && !is_cx231xx(state)) {
1421cb7a01acSMauro Carvalho Chehab 		switch (aud_input) {
1422cb7a01acSMauro Carvalho Chehab 		case CX25840_AUDIO_SERIAL:
1423cb7a01acSMauro Carvalho Chehab 			/* do nothing, use serial audio input */
1424cb7a01acSMauro Carvalho Chehab 			break;
142510a34367SMauro Carvalho Chehab 		case CX25840_AUDIO4:
142610a34367SMauro Carvalho Chehab 			reg &= ~0x30;
142710a34367SMauro Carvalho Chehab 			break;
142810a34367SMauro Carvalho Chehab 		case CX25840_AUDIO5:
142910a34367SMauro Carvalho Chehab 			reg &= ~0x30;
143010a34367SMauro Carvalho Chehab 			reg |= 0x10;
143110a34367SMauro Carvalho Chehab 			break;
143210a34367SMauro Carvalho Chehab 		case CX25840_AUDIO6:
143310a34367SMauro Carvalho Chehab 			reg &= ~0x30;
143410a34367SMauro Carvalho Chehab 			reg |= 0x20;
143510a34367SMauro Carvalho Chehab 			break;
143610a34367SMauro Carvalho Chehab 		case CX25840_AUDIO7:
143710a34367SMauro Carvalho Chehab 			reg &= ~0xc0;
143810a34367SMauro Carvalho Chehab 			break;
143910a34367SMauro Carvalho Chehab 		case CX25840_AUDIO8:
144010a34367SMauro Carvalho Chehab 			reg &= ~0xc0;
144110a34367SMauro Carvalho Chehab 			reg |= 0x40;
144210a34367SMauro Carvalho Chehab 			break;
1443cb7a01acSMauro Carvalho Chehab 		default:
1444cb7a01acSMauro Carvalho Chehab 			v4l_err(client, "0x%04x is not a valid audio input!\n",
1445cb7a01acSMauro Carvalho Chehab 				aud_input);
1446cb7a01acSMauro Carvalho Chehab 			return -EINVAL;
1447cb7a01acSMauro Carvalho Chehab 		}
1448cb7a01acSMauro Carvalho Chehab 	}
1449cb7a01acSMauro Carvalho Chehab 
1450cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x103, reg);
1451cb7a01acSMauro Carvalho Chehab 
1452cb7a01acSMauro Carvalho Chehab 	/* Set INPUT_MODE to Composite, S-Video or Component */
1453cb7a01acSMauro Carvalho Chehab 	if (is_component)
1454cb7a01acSMauro Carvalho Chehab 		cx25840_and_or(client, 0x401, ~0x6, 0x6);
1455cb7a01acSMauro Carvalho Chehab 	else
1456cb7a01acSMauro Carvalho Chehab 		cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02);
1457cb7a01acSMauro Carvalho Chehab 
1458cb7a01acSMauro Carvalho Chehab 	if (is_cx2388x(state)) {
1459cb7a01acSMauro Carvalho Chehab 		/* Enable or disable the DIF for tuner use */
1460cb7a01acSMauro Carvalho Chehab 		if (is_dif) {
1461cb7a01acSMauro Carvalho Chehab 			cx25840_and_or(client, 0x102, ~0x80, 0x80);
1462cb7a01acSMauro Carvalho Chehab 
1463cb7a01acSMauro Carvalho Chehab 			/* Set of defaults for NTSC and PAL */
1464cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x31c, 0xc2262600);
1465cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x320, 0xc2262600);
1466cb7a01acSMauro Carvalho Chehab 
1467cb7a01acSMauro Carvalho Chehab 			/* 18271 IF - Nobody else yet uses a different
1468cb7a01acSMauro Carvalho Chehab 			 * tuner with the DIF, so these are reasonable
1469cb7a01acSMauro Carvalho Chehab 			 * assumptions (HVR1250 and HVR1850 specific).
1470cb7a01acSMauro Carvalho Chehab 			 */
1471cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x318, 0xda262600);
1472cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x33c, 0x2a24c800);
1473cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x104, 0x0704dd00);
1474cb7a01acSMauro Carvalho Chehab 		} else {
1475cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x300, 0x015c28f5);
1476cb7a01acSMauro Carvalho Chehab 
1477cb7a01acSMauro Carvalho Chehab 			cx25840_and_or(client, 0x102, ~0x80, 0);
1478cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x340, 0xdf7df83);
1479cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x104, 0x0704dd80);
1480cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x314, 0x22400600);
1481cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x318, 0x40002600);
1482cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x324, 0x40002600);
1483cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x32c, 0x0250e620);
1484cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x39c, 0x01FF0B00);
1485cb7a01acSMauro Carvalho Chehab 
1486cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x410, 0xffff0dbf);
1487cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x414, 0x00137d03);
1488cb7a01acSMauro Carvalho Chehab 
1489038fd414SBrad Love 			if (is_cx23888(state)) {
1490038fd414SBrad Love 				/* 888 MISC_TIM_CTRL */
1491038fd414SBrad Love 				cx25840_write4(client, 0x42c, 0x42600000);
1492038fd414SBrad Love 				/* 888 FIELD_COUNT */
1493038fd414SBrad Love 				cx25840_write4(client, 0x430, 0x0000039b);
1494038fd414SBrad Love 				/* 888 VSCALE_CTRL */
1495038fd414SBrad Love 				cx25840_write4(client, 0x438, 0x00000000);
1496038fd414SBrad Love 				/* 888 DFE_CTRL1 */
1497038fd414SBrad Love 				cx25840_write4(client, 0x440, 0xF8E3E824);
1498038fd414SBrad Love 				/* 888 DFE_CTRL2 */
1499038fd414SBrad Love 				cx25840_write4(client, 0x444, 0x401040dc);
1500038fd414SBrad Love 				/* 888 DFE_CTRL3 */
1501038fd414SBrad Love 				cx25840_write4(client, 0x448, 0xcd3f02a0);
1502038fd414SBrad Love 				/* 888 PLL_CTRL */
1503038fd414SBrad Love 				cx25840_write4(client, 0x44c, 0x161f1000);
1504038fd414SBrad Love 				/* 888 HTL_CTRL */
1505038fd414SBrad Love 				cx25840_write4(client, 0x450, 0x00000802);
1506038fd414SBrad Love 			}
1507cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x91c, 0x01000000);
1508cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x8e0, 0x03063870);
1509cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x8d4, 0x7FFF0024);
1510cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x8d0, 0x00063073);
1511cb7a01acSMauro Carvalho Chehab 
1512cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x8c8, 0x00010000);
1513cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x8cc, 0x00080023);
1514cb7a01acSMauro Carvalho Chehab 
1515cb7a01acSMauro Carvalho Chehab 			/* DIF BYPASS */
1516cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, 0x33c, 0x2a04c800);
1517cb7a01acSMauro Carvalho Chehab 		}
1518cb7a01acSMauro Carvalho Chehab 
1519cb7a01acSMauro Carvalho Chehab 		/* Reset the DIF */
1520cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x398, 0);
1521cb7a01acSMauro Carvalho Chehab 	}
1522cb7a01acSMauro Carvalho Chehab 
1523cb7a01acSMauro Carvalho Chehab 	if (!is_cx2388x(state) && !is_cx231xx(state)) {
1524cb7a01acSMauro Carvalho Chehab 		/* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
1525cb7a01acSMauro Carvalho Chehab 		cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
1526cb7a01acSMauro Carvalho Chehab 		/* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */
1527cb7a01acSMauro Carvalho Chehab 		if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
1528cb7a01acSMauro Carvalho Chehab 			cx25840_and_or(client, 0x102, ~0x4, 4);
1529cb7a01acSMauro Carvalho Chehab 		else
1530cb7a01acSMauro Carvalho Chehab 			cx25840_and_or(client, 0x102, ~0x4, 0);
1531cb7a01acSMauro Carvalho Chehab 	} else {
1532cb7a01acSMauro Carvalho Chehab 		/* Set DUAL_MODE_ADC2 to 1 if component*/
1533cb7a01acSMauro Carvalho Chehab 		cx25840_and_or(client, 0x102, ~0x4, is_component ? 0x4 : 0x0);
1534cb7a01acSMauro Carvalho Chehab 		if (is_composite) {
1535cb7a01acSMauro Carvalho Chehab 			/* ADC2 input select channel 2 */
1536cb7a01acSMauro Carvalho Chehab 			cx25840_and_or(client, 0x102, ~0x2, 0);
1537cb7a01acSMauro Carvalho Chehab 		} else if (!is_component) {
1538cb7a01acSMauro Carvalho Chehab 			/* S-Video */
1539cb7a01acSMauro Carvalho Chehab 			if (chroma >= CX25840_SVIDEO_CHROMA7) {
1540cb7a01acSMauro Carvalho Chehab 				/* ADC2 input select channel 3 */
1541cb7a01acSMauro Carvalho Chehab 				cx25840_and_or(client, 0x102, ~0x2, 2);
1542cb7a01acSMauro Carvalho Chehab 			} else {
1543cb7a01acSMauro Carvalho Chehab 				/* ADC2 input select channel 2 */
1544cb7a01acSMauro Carvalho Chehab 				cx25840_and_or(client, 0x102, ~0x2, 0);
1545cb7a01acSMauro Carvalho Chehab 			}
1546cb7a01acSMauro Carvalho Chehab 		}
1547cb7a01acSMauro Carvalho Chehab 
1548cb7a01acSMauro Carvalho Chehab 		/* cx23885 / SVIDEO */
1549cb7a01acSMauro Carvalho Chehab 		if (is_cx2388x(state) && is_svideo) {
1550cb7a01acSMauro Carvalho Chehab #define AFE_CTRL  (0x104)
1551cb7a01acSMauro Carvalho Chehab #define MODE_CTRL (0x400)
1552cb7a01acSMauro Carvalho Chehab 			cx25840_and_or(client, 0x102, ~0x2, 0x2);
1553cb7a01acSMauro Carvalho Chehab 
1554cb7a01acSMauro Carvalho Chehab 			val = cx25840_read4(client, MODE_CTRL);
1555cb7a01acSMauro Carvalho Chehab 			val &= 0xFFFFF9FF;
1556cb7a01acSMauro Carvalho Chehab 
1557cb7a01acSMauro Carvalho Chehab 			/* YC */
1558cb7a01acSMauro Carvalho Chehab 			val |= 0x00000200;
1559cb7a01acSMauro Carvalho Chehab 			val &= ~0x2000;
1560cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, MODE_CTRL, val);
1561cb7a01acSMauro Carvalho Chehab 
1562cb7a01acSMauro Carvalho Chehab 			val = cx25840_read4(client, AFE_CTRL);
1563cb7a01acSMauro Carvalho Chehab 
1564cb7a01acSMauro Carvalho Chehab 			/* Chroma in select */
1565cb7a01acSMauro Carvalho Chehab 			val |= 0x00001000;
1566cb7a01acSMauro Carvalho Chehab 			val &= 0xfffffe7f;
1567cb7a01acSMauro Carvalho Chehab 			/* Clear VGA_SEL_CH2 and VGA_SEL_CH3 (bits 7 and 8).
1568cb7a01acSMauro Carvalho Chehab 			 * This sets them to use video rather than audio.
1569cb7a01acSMauro Carvalho Chehab 			 * Only one of the two will be in use.
1570cb7a01acSMauro Carvalho Chehab 			 */
1571cb7a01acSMauro Carvalho Chehab 			cx25840_write4(client, AFE_CTRL, val);
157210a34367SMauro Carvalho Chehab 		} else {
1573cb7a01acSMauro Carvalho Chehab 			cx25840_and_or(client, 0x102, ~0x2, 0);
1574cb7a01acSMauro Carvalho Chehab 		}
157510a34367SMauro Carvalho Chehab 	}
1576cb7a01acSMauro Carvalho Chehab 
1577cb7a01acSMauro Carvalho Chehab 	state->vid_input = vid_input;
1578cb7a01acSMauro Carvalho Chehab 	state->aud_input = aud_input;
1579cb7a01acSMauro Carvalho Chehab 	cx25840_audio_set_path(client);
1580cb7a01acSMauro Carvalho Chehab 	input_change(client);
1581cb7a01acSMauro Carvalho Chehab 
1582cb7a01acSMauro Carvalho Chehab 	if (is_cx2388x(state)) {
1583cb7a01acSMauro Carvalho Chehab 		/* Audio channel 1 src : Parallel 1 */
1584cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x124, 0x03);
1585cb7a01acSMauro Carvalho Chehab 
1586cb7a01acSMauro Carvalho Chehab 		/* Select AFE clock pad output source */
1587cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x144, 0x05);
1588cb7a01acSMauro Carvalho Chehab 
1589cb7a01acSMauro Carvalho Chehab 		/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
1590cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x914, 0xa0);
1591cb7a01acSMauro Carvalho Chehab 
1592cb7a01acSMauro Carvalho Chehab 		/* I2S_OUT_CTL:
1593cb7a01acSMauro Carvalho Chehab 		 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
1594cb7a01acSMauro Carvalho Chehab 		 * I2S_OUT_MASTER_MODE = Master
1595cb7a01acSMauro Carvalho Chehab 		 */
1596cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x918, 0xa0);
1597cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x919, 0x01);
1598cb7a01acSMauro Carvalho Chehab 	} else if (is_cx231xx(state)) {
1599cb7a01acSMauro Carvalho Chehab 		/* Audio channel 1 src : Parallel 1 */
1600cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x124, 0x03);
1601cb7a01acSMauro Carvalho Chehab 
1602cb7a01acSMauro Carvalho Chehab 		/* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */
1603cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x914, 0xa0);
1604cb7a01acSMauro Carvalho Chehab 
1605cb7a01acSMauro Carvalho Chehab 		/* I2S_OUT_CTL:
1606cb7a01acSMauro Carvalho Chehab 		 * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1
1607cb7a01acSMauro Carvalho Chehab 		 * I2S_OUT_MASTER_MODE = Master
1608cb7a01acSMauro Carvalho Chehab 		 */
1609cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x918, 0xa0);
1610cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x919, 0x01);
1611cb7a01acSMauro Carvalho Chehab 	}
1612cb7a01acSMauro Carvalho Chehab 
161310a34367SMauro Carvalho Chehab 	if (is_cx2388x(state) &&
161410a34367SMauro Carvalho Chehab 	    ((aud_input == CX25840_AUDIO7) || (aud_input == CX25840_AUDIO6))) {
1615cb7a01acSMauro Carvalho Chehab 		/* Configure audio from LR1 or LR2 input */
1616cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x910, 0);
1617cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x8d0, 0x63073);
161810a34367SMauro Carvalho Chehab 	} else if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) {
1619cb7a01acSMauro Carvalho Chehab 		/* Configure audio from tuner/sif input */
1620cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x910, 0x12b000c9);
1621cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x8d0, 0x1f063870);
1622cb7a01acSMauro Carvalho Chehab 	}
1623cb7a01acSMauro Carvalho Chehab 
1624cb7a01acSMauro Carvalho Chehab 	if (is_cx23888(state)) {
162510a34367SMauro Carvalho Chehab 		/*
162610a34367SMauro Carvalho Chehab 		 * HVR1850
162710a34367SMauro Carvalho Chehab 		 *
162810a34367SMauro Carvalho Chehab 		 * AUD_IO_CTRL - I2S Input, Parallel1
162910a34367SMauro Carvalho Chehab 		 *  - Channel 1 src - Parallel1 (Merlin out)
163010a34367SMauro Carvalho Chehab 		 *  - Channel 2 src - Parallel2 (Merlin out)
163110a34367SMauro Carvalho Chehab 		 *  - Channel 3 src - Parallel3 (Merlin AC97 out)
163210a34367SMauro Carvalho Chehab 		 *  - I2S source and dir - Merlin, output
163310a34367SMauro Carvalho Chehab 		 */
1634cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x124, 0x100);
1635cb7a01acSMauro Carvalho Chehab 
1636cb7a01acSMauro Carvalho Chehab 		if (!is_dif) {
163710a34367SMauro Carvalho Chehab 			/*
163810a34367SMauro Carvalho Chehab 			 * Stop microcontroller if we don't need it
1639cb7a01acSMauro Carvalho Chehab 			 * to avoid audio popping on svideo/composite use.
1640cb7a01acSMauro Carvalho Chehab 			 */
1641cb7a01acSMauro Carvalho Chehab 			cx25840_and_or(client, 0x803, ~0x10, 0x00);
1642cb7a01acSMauro Carvalho Chehab 		}
1643cb7a01acSMauro Carvalho Chehab 	}
1644cb7a01acSMauro Carvalho Chehab 
1645cb7a01acSMauro Carvalho Chehab 	return 0;
1646cb7a01acSMauro Carvalho Chehab }
1647cb7a01acSMauro Carvalho Chehab 
1648cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1649cb7a01acSMauro Carvalho Chehab 
set_v4lstd(struct i2c_client * client)1650cb7a01acSMauro Carvalho Chehab static int set_v4lstd(struct i2c_client *client)
1651cb7a01acSMauro Carvalho Chehab {
1652cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
1653cb7a01acSMauro Carvalho Chehab 	u8 fmt = 0;	/* zero is autodetect */
1654cb7a01acSMauro Carvalho Chehab 	u8 pal_m = 0;
1655cb7a01acSMauro Carvalho Chehab 
1656cb7a01acSMauro Carvalho Chehab 	/* First tests should be against specific std */
1657cb7a01acSMauro Carvalho Chehab 	if (state->std == V4L2_STD_NTSC_M_JP) {
1658cb7a01acSMauro Carvalho Chehab 		fmt = 0x2;
1659cb7a01acSMauro Carvalho Chehab 	} else if (state->std == V4L2_STD_NTSC_443) {
1660cb7a01acSMauro Carvalho Chehab 		fmt = 0x3;
1661cb7a01acSMauro Carvalho Chehab 	} else if (state->std == V4L2_STD_PAL_M) {
1662cb7a01acSMauro Carvalho Chehab 		pal_m = 1;
1663cb7a01acSMauro Carvalho Chehab 		fmt = 0x5;
1664cb7a01acSMauro Carvalho Chehab 	} else if (state->std == V4L2_STD_PAL_N) {
1665cb7a01acSMauro Carvalho Chehab 		fmt = 0x6;
1666cb7a01acSMauro Carvalho Chehab 	} else if (state->std == V4L2_STD_PAL_Nc) {
1667cb7a01acSMauro Carvalho Chehab 		fmt = 0x7;
1668cb7a01acSMauro Carvalho Chehab 	} else if (state->std == V4L2_STD_PAL_60) {
1669cb7a01acSMauro Carvalho Chehab 		fmt = 0x8;
1670cb7a01acSMauro Carvalho Chehab 	} else {
1671cb7a01acSMauro Carvalho Chehab 		/* Then, test against generic ones */
1672cb7a01acSMauro Carvalho Chehab 		if (state->std & V4L2_STD_NTSC)
1673cb7a01acSMauro Carvalho Chehab 			fmt = 0x1;
1674cb7a01acSMauro Carvalho Chehab 		else if (state->std & V4L2_STD_PAL)
1675cb7a01acSMauro Carvalho Chehab 			fmt = 0x4;
1676cb7a01acSMauro Carvalho Chehab 		else if (state->std & V4L2_STD_SECAM)
1677cb7a01acSMauro Carvalho Chehab 			fmt = 0xc;
1678cb7a01acSMauro Carvalho Chehab 	}
1679cb7a01acSMauro Carvalho Chehab 
168010a34367SMauro Carvalho Chehab 	v4l_dbg(1, cx25840_debug, client,
168110a34367SMauro Carvalho Chehab 		"changing video std to fmt %i\n", fmt);
1682cb7a01acSMauro Carvalho Chehab 
168310a34367SMauro Carvalho Chehab 	/*
168410a34367SMauro Carvalho Chehab 	 * Follow step 9 of section 3.16 in the cx25840 datasheet.
168510a34367SMauro Carvalho Chehab 	 * Without this PAL may display a vertical ghosting effect.
168610a34367SMauro Carvalho Chehab 	 * This happens for example with the Yuan MPC622.
168710a34367SMauro Carvalho Chehab 	 */
1688cb7a01acSMauro Carvalho Chehab 	if (fmt >= 4 && fmt < 8) {
1689cb7a01acSMauro Carvalho Chehab 		/* Set format to NTSC-M */
1690cb7a01acSMauro Carvalho Chehab 		cx25840_and_or(client, 0x400, ~0xf, 1);
1691cb7a01acSMauro Carvalho Chehab 		/* Turn off LCOMB */
1692cb7a01acSMauro Carvalho Chehab 		cx25840_and_or(client, 0x47b, ~6, 0);
1693cb7a01acSMauro Carvalho Chehab 	}
1694cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x400, ~0xf, fmt);
1695cb7a01acSMauro Carvalho Chehab 	cx25840_and_or(client, 0x403, ~0x3, pal_m);
1696cb7a01acSMauro Carvalho Chehab 	if (is_cx23888(state))
1697cb7a01acSMauro Carvalho Chehab 		cx23888_std_setup(client);
1698cb7a01acSMauro Carvalho Chehab 	else
1699cb7a01acSMauro Carvalho Chehab 		cx25840_std_setup(client);
1700cb7a01acSMauro Carvalho Chehab 	if (!is_cx2583x(state))
1701cb7a01acSMauro Carvalho Chehab 		input_change(client);
1702cb7a01acSMauro Carvalho Chehab 	return 0;
1703cb7a01acSMauro Carvalho Chehab }
1704cb7a01acSMauro Carvalho Chehab 
1705cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1706cb7a01acSMauro Carvalho Chehab 
cx25840_s_ctrl(struct v4l2_ctrl * ctrl)1707cb7a01acSMauro Carvalho Chehab static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl)
1708cb7a01acSMauro Carvalho Chehab {
1709cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = to_sd(ctrl);
1710cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
1711cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
1712cb7a01acSMauro Carvalho Chehab 
1713cb7a01acSMauro Carvalho Chehab 	switch (ctrl->id) {
1714cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_BRIGHTNESS:
1715cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x414, ctrl->val - 128);
1716cb7a01acSMauro Carvalho Chehab 		break;
1717cb7a01acSMauro Carvalho Chehab 
1718cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_CONTRAST:
1719cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x415, ctrl->val << 1);
1720cb7a01acSMauro Carvalho Chehab 		break;
1721cb7a01acSMauro Carvalho Chehab 
1722cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_SATURATION:
1723cb7a01acSMauro Carvalho Chehab 		if (is_cx23888(state)) {
1724cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x418, ctrl->val << 1);
1725cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x419, ctrl->val << 1);
1726cb7a01acSMauro Carvalho Chehab 		} else {
1727cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x420, ctrl->val << 1);
1728cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x421, ctrl->val << 1);
1729cb7a01acSMauro Carvalho Chehab 		}
1730cb7a01acSMauro Carvalho Chehab 		break;
1731cb7a01acSMauro Carvalho Chehab 
1732cb7a01acSMauro Carvalho Chehab 	case V4L2_CID_HUE:
1733cb7a01acSMauro Carvalho Chehab 		if (is_cx23888(state))
1734cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x41a, ctrl->val);
1735cb7a01acSMauro Carvalho Chehab 		else
1736cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x422, ctrl->val);
1737cb7a01acSMauro Carvalho Chehab 		break;
1738cb7a01acSMauro Carvalho Chehab 
1739cb7a01acSMauro Carvalho Chehab 	default:
1740cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1741cb7a01acSMauro Carvalho Chehab 	}
1742cb7a01acSMauro Carvalho Chehab 
1743cb7a01acSMauro Carvalho Chehab 	return 0;
1744cb7a01acSMauro Carvalho Chehab }
1745cb7a01acSMauro Carvalho Chehab 
1746cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1747cb7a01acSMauro Carvalho Chehab 
cx25840_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)17486e80c473SHans Verkuil static int cx25840_set_fmt(struct v4l2_subdev *sd,
17490d346d2aSTomi Valkeinen 			   struct v4l2_subdev_state *sd_state,
17506e80c473SHans Verkuil 			   struct v4l2_subdev_format *format)
1751cb7a01acSMauro Carvalho Chehab {
17526e80c473SHans Verkuil 	struct v4l2_mbus_framefmt *fmt = &format->format;
1753cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
1754cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
175510a34367SMauro Carvalho Chehab 	u32 hsc, vsc, v_src, h_src, v_add;
175665efeca0SMaciej S. Szmigiero 	int filter;
175710a34367SMauro Carvalho Chehab 	int is_50hz = !(state->std & V4L2_STD_525_60);
1758cb7a01acSMauro Carvalho Chehab 
17596e80c473SHans Verkuil 	if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED)
1760cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
1761cb7a01acSMauro Carvalho Chehab 
1762cb7a01acSMauro Carvalho Chehab 	fmt->field = V4L2_FIELD_INTERLACED;
1763cb7a01acSMauro Carvalho Chehab 	fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
1764cb7a01acSMauro Carvalho Chehab 
1765cb7a01acSMauro Carvalho Chehab 	if (is_cx23888(state)) {
176610a34367SMauro Carvalho Chehab 		v_src = (cx25840_read(client, 0x42a) & 0x3f) << 4;
176710a34367SMauro Carvalho Chehab 		v_src |= (cx25840_read(client, 0x429) & 0xf0) >> 4;
1768cb7a01acSMauro Carvalho Chehab 	} else {
176910a34367SMauro Carvalho Chehab 		v_src = (cx25840_read(client, 0x476) & 0x3f) << 4;
177010a34367SMauro Carvalho Chehab 		v_src |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
1771cb7a01acSMauro Carvalho Chehab 	}
1772cb7a01acSMauro Carvalho Chehab 
1773cb7a01acSMauro Carvalho Chehab 	if (is_cx23888(state)) {
177410a34367SMauro Carvalho Chehab 		h_src = (cx25840_read(client, 0x426) & 0x3f) << 4;
177510a34367SMauro Carvalho Chehab 		h_src |= (cx25840_read(client, 0x425) & 0xf0) >> 4;
1776cb7a01acSMauro Carvalho Chehab 	} else {
177710a34367SMauro Carvalho Chehab 		h_src = (cx25840_read(client, 0x472) & 0x3f) << 4;
177810a34367SMauro Carvalho Chehab 		h_src |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
1779cb7a01acSMauro Carvalho Chehab 	}
1780cb7a01acSMauro Carvalho Chehab 
178165efeca0SMaciej S. Szmigiero 	if (!state->generic_mode) {
178210a34367SMauro Carvalho Chehab 		v_add = is_50hz ? 4 : 7;
1783cb7a01acSMauro Carvalho Chehab 
1784499ebed3SHans Verkuil 		/*
178565efeca0SMaciej S. Szmigiero 		 * cx23888 in 525-line mode is programmed for 486 active lines
178665efeca0SMaciej S. Szmigiero 		 * while other chips use 487 active lines.
178765efeca0SMaciej S. Szmigiero 		 *
178865efeca0SMaciej S. Szmigiero 		 * See reg 0x428 bits [21:12] in cx23888_std_setup() vs
178965efeca0SMaciej S. Szmigiero 		 * vactive in cx25840_std_setup().
1790499ebed3SHans Verkuil 		 */
179110a34367SMauro Carvalho Chehab 		if (is_cx23888(state) && !is_50hz)
179210a34367SMauro Carvalho Chehab 			v_add--;
179310a34367SMauro Carvalho Chehab 	} else {
179410a34367SMauro Carvalho Chehab 		v_add = 0;
179510a34367SMauro Carvalho Chehab 	}
179665efeca0SMaciej S. Szmigiero 
179710a34367SMauro Carvalho Chehab 	if (h_src == 0 ||
179810a34367SMauro Carvalho Chehab 	    v_src <= v_add) {
179965efeca0SMaciej S. Szmigiero 		v4l_err(client,
180065efeca0SMaciej S. Szmigiero 			"chip reported picture size (%u x %u) is far too small\n",
180110a34367SMauro Carvalho Chehab 			(unsigned int)h_src, (unsigned int)v_src);
180265efeca0SMaciej S. Szmigiero 		/*
180365efeca0SMaciej S. Szmigiero 		 * that's the best we can do since the output picture
180465efeca0SMaciej S. Szmigiero 		 * size is completely unknown in this case
180565efeca0SMaciej S. Szmigiero 		 */
180665efeca0SMaciej S. Szmigiero 		return -EINVAL;
1807cb7a01acSMauro Carvalho Chehab 	}
180865efeca0SMaciej S. Szmigiero 
180910a34367SMauro Carvalho Chehab 	fmt->width = clamp(fmt->width, (h_src + 15) / 16, h_src);
181065efeca0SMaciej S. Szmigiero 
181110a34367SMauro Carvalho Chehab 	if (v_add * 8 >= v_src)
181210a34367SMauro Carvalho Chehab 		fmt->height = clamp(fmt->height, (u32)1, v_src - v_add);
181365efeca0SMaciej S. Szmigiero 	else
181410a34367SMauro Carvalho Chehab 		fmt->height = clamp(fmt->height, (v_src - v_add * 8 + 7) / 8,
181510a34367SMauro Carvalho Chehab 				    v_src - v_add);
181665efeca0SMaciej S. Szmigiero 
18176e80c473SHans Verkuil 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
18186e80c473SHans Verkuil 		return 0;
1819cb7a01acSMauro Carvalho Chehab 
182010a34367SMauro Carvalho Chehab 	hsc = (h_src * (1 << 20)) / fmt->width - (1 << 20);
182110a34367SMauro Carvalho Chehab 	vsc = (1 << 16) - (v_src * (1 << 9) / (fmt->height + v_add) - (1 << 9));
182210a34367SMauro Carvalho Chehab 	vsc &= 0x1fff;
1823cb7a01acSMauro Carvalho Chehab 
1824cb7a01acSMauro Carvalho Chehab 	if (fmt->width >= 385)
1825cb7a01acSMauro Carvalho Chehab 		filter = 0;
1826cb7a01acSMauro Carvalho Chehab 	else if (fmt->width > 192)
1827cb7a01acSMauro Carvalho Chehab 		filter = 1;
1828cb7a01acSMauro Carvalho Chehab 	else if (fmt->width > 96)
1829cb7a01acSMauro Carvalho Chehab 		filter = 2;
1830cb7a01acSMauro Carvalho Chehab 	else
1831cb7a01acSMauro Carvalho Chehab 		filter = 3;
1832cb7a01acSMauro Carvalho Chehab 
183365efeca0SMaciej S. Szmigiero 	v4l_dbg(1, cx25840_debug, client,
183465efeca0SMaciej S. Szmigiero 		"decoder set size %u x %u with scale %x x %x\n",
183565efeca0SMaciej S. Szmigiero 		(unsigned int)fmt->width, (unsigned int)fmt->height,
183610a34367SMauro Carvalho Chehab 		(unsigned int)hsc, (unsigned int)vsc);
1837cb7a01acSMauro Carvalho Chehab 
183810a34367SMauro Carvalho Chehab 	/* HSCALE=hsc */
1839ee61cd9fSHans Verkuil 	if (is_cx23888(state)) {
184010a34367SMauro Carvalho Chehab 		cx25840_write4(client, 0x434, hsc | (1 << 24));
184110a34367SMauro Carvalho Chehab 		/* VSCALE=vsc VS_INTRLACE=1 VFILT=filter */
184210a34367SMauro Carvalho Chehab 		cx25840_write4(client, 0x438, vsc | (1 << 19) | (filter << 16));
1843ee61cd9fSHans Verkuil 	} else {
184410a34367SMauro Carvalho Chehab 		cx25840_write(client, 0x418, hsc & 0xff);
184510a34367SMauro Carvalho Chehab 		cx25840_write(client, 0x419, (hsc >> 8) & 0xff);
184610a34367SMauro Carvalho Chehab 		cx25840_write(client, 0x41a, hsc >> 16);
184710a34367SMauro Carvalho Chehab 		/* VSCALE=vsc */
184810a34367SMauro Carvalho Chehab 		cx25840_write(client, 0x41c, vsc & 0xff);
184910a34367SMauro Carvalho Chehab 		cx25840_write(client, 0x41d, vsc >> 8);
1850cb7a01acSMauro Carvalho Chehab 		/* VS_INTRLACE=1 VFILT=filter */
1851cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x41e, 0x8 | filter);
1852ee61cd9fSHans Verkuil 	}
1853cb7a01acSMauro Carvalho Chehab 	return 0;
1854cb7a01acSMauro Carvalho Chehab }
1855cb7a01acSMauro Carvalho Chehab 
1856cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1857cb7a01acSMauro Carvalho Chehab 
log_video_status(struct i2c_client * client)1858cb7a01acSMauro Carvalho Chehab static void log_video_status(struct i2c_client *client)
1859cb7a01acSMauro Carvalho Chehab {
1860cb7a01acSMauro Carvalho Chehab 	static const char *const fmt_strs[] = {
1861cb7a01acSMauro Carvalho Chehab 		"0x0",
1862cb7a01acSMauro Carvalho Chehab 		"NTSC-M", "NTSC-J", "NTSC-4.43",
1863cb7a01acSMauro Carvalho Chehab 		"PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
1864cb7a01acSMauro Carvalho Chehab 		"0x9", "0xA", "0xB",
1865cb7a01acSMauro Carvalho Chehab 		"SECAM",
1866cb7a01acSMauro Carvalho Chehab 		"0xD", "0xE", "0xF"
1867cb7a01acSMauro Carvalho Chehab 	};
1868cb7a01acSMauro Carvalho Chehab 
1869cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
1870cb7a01acSMauro Carvalho Chehab 	u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
1871cb7a01acSMauro Carvalho Chehab 	u8 gen_stat1 = cx25840_read(client, 0x40d);
1872cb7a01acSMauro Carvalho Chehab 	u8 gen_stat2 = cx25840_read(client, 0x40e);
1873cb7a01acSMauro Carvalho Chehab 	int vid_input = state->vid_input;
1874cb7a01acSMauro Carvalho Chehab 
1875cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "Video signal:              %spresent\n",
1876cb7a01acSMauro Carvalho Chehab 		 (gen_stat2 & 0x20) ? "" : "not ");
1877cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "Detected format:           %s\n",
1878cb7a01acSMauro Carvalho Chehab 		 fmt_strs[gen_stat1 & 0xf]);
1879cb7a01acSMauro Carvalho Chehab 
1880cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "Specified standard:        %s\n",
1881cb7a01acSMauro Carvalho Chehab 		 vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
1882cb7a01acSMauro Carvalho Chehab 
1883cb7a01acSMauro Carvalho Chehab 	if (vid_input >= CX25840_COMPOSITE1 &&
1884cb7a01acSMauro Carvalho Chehab 	    vid_input <= CX25840_COMPOSITE8) {
1885cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "Specified video input:     Composite %d\n",
1886cb7a01acSMauro Carvalho Chehab 			 vid_input - CX25840_COMPOSITE1 + 1);
1887cb7a01acSMauro Carvalho Chehab 	} else {
188810a34367SMauro Carvalho Chehab 		v4l_info(client,
188910a34367SMauro Carvalho Chehab 			 "Specified video input:     S-Video (Luma In%d, Chroma In%d)\n",
1890cb7a01acSMauro Carvalho Chehab 			 (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
1891cb7a01acSMauro Carvalho Chehab 	}
1892cb7a01acSMauro Carvalho Chehab 
189310a34367SMauro Carvalho Chehab 	v4l_info(client, "Specified audioclock freq: %d Hz\n",
189410a34367SMauro Carvalho Chehab 		 state->audclk_freq);
1895cb7a01acSMauro Carvalho Chehab }
1896cb7a01acSMauro Carvalho Chehab 
1897cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
1898cb7a01acSMauro Carvalho Chehab 
log_audio_status(struct i2c_client * client)1899cb7a01acSMauro Carvalho Chehab static void log_audio_status(struct i2c_client *client)
1900cb7a01acSMauro Carvalho Chehab {
1901cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
1902cb7a01acSMauro Carvalho Chehab 	u8 download_ctl = cx25840_read(client, 0x803);
1903cb7a01acSMauro Carvalho Chehab 	u8 mod_det_stat0 = cx25840_read(client, 0x804);
1904cb7a01acSMauro Carvalho Chehab 	u8 mod_det_stat1 = cx25840_read(client, 0x805);
1905cb7a01acSMauro Carvalho Chehab 	u8 audio_config = cx25840_read(client, 0x808);
1906cb7a01acSMauro Carvalho Chehab 	u8 pref_mode = cx25840_read(client, 0x809);
1907cb7a01acSMauro Carvalho Chehab 	u8 afc0 = cx25840_read(client, 0x80b);
1908cb7a01acSMauro Carvalho Chehab 	u8 mute_ctl = cx25840_read(client, 0x8d3);
1909cb7a01acSMauro Carvalho Chehab 	int aud_input = state->aud_input;
1910cb7a01acSMauro Carvalho Chehab 	char *p;
1911cb7a01acSMauro Carvalho Chehab 
1912cb7a01acSMauro Carvalho Chehab 	switch (mod_det_stat0) {
191310a34367SMauro Carvalho Chehab 	case 0x00:
191410a34367SMauro Carvalho Chehab 		p = "mono";
191510a34367SMauro Carvalho Chehab 		break;
191610a34367SMauro Carvalho Chehab 	case 0x01:
191710a34367SMauro Carvalho Chehab 		p = "stereo";
191810a34367SMauro Carvalho Chehab 		break;
191910a34367SMauro Carvalho Chehab 	case 0x02:
192010a34367SMauro Carvalho Chehab 		p = "dual";
192110a34367SMauro Carvalho Chehab 		break;
192210a34367SMauro Carvalho Chehab 	case 0x04:
192310a34367SMauro Carvalho Chehab 		p = "tri";
192410a34367SMauro Carvalho Chehab 		break;
192510a34367SMauro Carvalho Chehab 	case 0x10:
192610a34367SMauro Carvalho Chehab 		p = "mono with SAP";
192710a34367SMauro Carvalho Chehab 		break;
192810a34367SMauro Carvalho Chehab 	case 0x11:
192910a34367SMauro Carvalho Chehab 		p = "stereo with SAP";
193010a34367SMauro Carvalho Chehab 		break;
193110a34367SMauro Carvalho Chehab 	case 0x12:
193210a34367SMauro Carvalho Chehab 		p = "dual with SAP";
193310a34367SMauro Carvalho Chehab 		break;
193410a34367SMauro Carvalho Chehab 	case 0x14:
193510a34367SMauro Carvalho Chehab 		p = "tri with SAP";
193610a34367SMauro Carvalho Chehab 		break;
193710a34367SMauro Carvalho Chehab 	case 0xfe:
193810a34367SMauro Carvalho Chehab 		p = "forced mode";
193910a34367SMauro Carvalho Chehab 		break;
194010a34367SMauro Carvalho Chehab 	default:
194110a34367SMauro Carvalho Chehab 		p = "not defined";
1942cb7a01acSMauro Carvalho Chehab 	}
1943cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "Detected audio mode:       %s\n", p);
1944cb7a01acSMauro Carvalho Chehab 
1945cb7a01acSMauro Carvalho Chehab 	switch (mod_det_stat1) {
194610a34367SMauro Carvalho Chehab 	case 0x00:
194710a34367SMauro Carvalho Chehab 		p = "not defined";
194810a34367SMauro Carvalho Chehab 		break;
194910a34367SMauro Carvalho Chehab 	case 0x01:
195010a34367SMauro Carvalho Chehab 		p = "EIAJ";
195110a34367SMauro Carvalho Chehab 		break;
195210a34367SMauro Carvalho Chehab 	case 0x02:
195310a34367SMauro Carvalho Chehab 		p = "A2-M";
195410a34367SMauro Carvalho Chehab 		break;
195510a34367SMauro Carvalho Chehab 	case 0x03:
195610a34367SMauro Carvalho Chehab 		p = "A2-BG";
195710a34367SMauro Carvalho Chehab 		break;
195810a34367SMauro Carvalho Chehab 	case 0x04:
195910a34367SMauro Carvalho Chehab 		p = "A2-DK1";
196010a34367SMauro Carvalho Chehab 		break;
196110a34367SMauro Carvalho Chehab 	case 0x05:
196210a34367SMauro Carvalho Chehab 		p = "A2-DK2";
196310a34367SMauro Carvalho Chehab 		break;
196410a34367SMauro Carvalho Chehab 	case 0x06:
196510a34367SMauro Carvalho Chehab 		p = "A2-DK3";
196610a34367SMauro Carvalho Chehab 		break;
196710a34367SMauro Carvalho Chehab 	case 0x07:
196810a34367SMauro Carvalho Chehab 		p = "A1 (6.0 MHz FM Mono)";
196910a34367SMauro Carvalho Chehab 		break;
197010a34367SMauro Carvalho Chehab 	case 0x08:
197110a34367SMauro Carvalho Chehab 		p = "AM-L";
197210a34367SMauro Carvalho Chehab 		break;
197310a34367SMauro Carvalho Chehab 	case 0x09:
197410a34367SMauro Carvalho Chehab 		p = "NICAM-BG";
197510a34367SMauro Carvalho Chehab 		break;
197610a34367SMauro Carvalho Chehab 	case 0x0a:
197710a34367SMauro Carvalho Chehab 		p = "NICAM-DK";
197810a34367SMauro Carvalho Chehab 		break;
197910a34367SMauro Carvalho Chehab 	case 0x0b:
198010a34367SMauro Carvalho Chehab 		p = "NICAM-I";
198110a34367SMauro Carvalho Chehab 		break;
198210a34367SMauro Carvalho Chehab 	case 0x0c:
198310a34367SMauro Carvalho Chehab 		p = "NICAM-L";
198410a34367SMauro Carvalho Chehab 		break;
198510a34367SMauro Carvalho Chehab 	case 0x0d:
198610a34367SMauro Carvalho Chehab 		p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)";
198710a34367SMauro Carvalho Chehab 		break;
198810a34367SMauro Carvalho Chehab 	case 0x0e:
198910a34367SMauro Carvalho Chehab 		p = "IF FM Radio";
199010a34367SMauro Carvalho Chehab 		break;
199110a34367SMauro Carvalho Chehab 	case 0x0f:
199210a34367SMauro Carvalho Chehab 		p = "BTSC";
199310a34367SMauro Carvalho Chehab 		break;
199410a34367SMauro Carvalho Chehab 	case 0x10:
199510a34367SMauro Carvalho Chehab 		p = "high-deviation FM";
199610a34367SMauro Carvalho Chehab 		break;
199710a34367SMauro Carvalho Chehab 	case 0x11:
199810a34367SMauro Carvalho Chehab 		p = "very high-deviation FM";
199910a34367SMauro Carvalho Chehab 		break;
200010a34367SMauro Carvalho Chehab 	case 0xfd:
200110a34367SMauro Carvalho Chehab 		p = "unknown audio standard";
200210a34367SMauro Carvalho Chehab 		break;
200310a34367SMauro Carvalho Chehab 	case 0xfe:
200410a34367SMauro Carvalho Chehab 		p = "forced audio standard";
200510a34367SMauro Carvalho Chehab 		break;
200610a34367SMauro Carvalho Chehab 	case 0xff:
200710a34367SMauro Carvalho Chehab 		p = "no detected audio standard";
200810a34367SMauro Carvalho Chehab 		break;
200910a34367SMauro Carvalho Chehab 	default:
201010a34367SMauro Carvalho Chehab 		p = "not defined";
2011cb7a01acSMauro Carvalho Chehab 	}
2012cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "Detected audio standard:   %s\n", p);
2013cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "Audio microcontroller:     %s\n",
2014cb7a01acSMauro Carvalho Chehab 		 (download_ctl & 0x10) ?
2015cb7a01acSMauro Carvalho Chehab 		 ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
2016cb7a01acSMauro Carvalho Chehab 
2017cb7a01acSMauro Carvalho Chehab 	switch (audio_config >> 4) {
201810a34367SMauro Carvalho Chehab 	case 0x00:
201910a34367SMauro Carvalho Chehab 		p = "undefined";
202010a34367SMauro Carvalho Chehab 		break;
202110a34367SMauro Carvalho Chehab 	case 0x01:
202210a34367SMauro Carvalho Chehab 		p = "BTSC";
202310a34367SMauro Carvalho Chehab 		break;
202410a34367SMauro Carvalho Chehab 	case 0x02:
202510a34367SMauro Carvalho Chehab 		p = "EIAJ";
202610a34367SMauro Carvalho Chehab 		break;
202710a34367SMauro Carvalho Chehab 	case 0x03:
202810a34367SMauro Carvalho Chehab 		p = "A2-M";
202910a34367SMauro Carvalho Chehab 		break;
203010a34367SMauro Carvalho Chehab 	case 0x04:
203110a34367SMauro Carvalho Chehab 		p = "A2-BG";
203210a34367SMauro Carvalho Chehab 		break;
203310a34367SMauro Carvalho Chehab 	case 0x05:
203410a34367SMauro Carvalho Chehab 		p = "A2-DK1";
203510a34367SMauro Carvalho Chehab 		break;
203610a34367SMauro Carvalho Chehab 	case 0x06:
203710a34367SMauro Carvalho Chehab 		p = "A2-DK2";
203810a34367SMauro Carvalho Chehab 		break;
203910a34367SMauro Carvalho Chehab 	case 0x07:
204010a34367SMauro Carvalho Chehab 		p = "A2-DK3";
204110a34367SMauro Carvalho Chehab 		break;
204210a34367SMauro Carvalho Chehab 	case 0x08:
204310a34367SMauro Carvalho Chehab 		p = "A1 (6.0 MHz FM Mono)";
204410a34367SMauro Carvalho Chehab 		break;
204510a34367SMauro Carvalho Chehab 	case 0x09:
204610a34367SMauro Carvalho Chehab 		p = "AM-L";
204710a34367SMauro Carvalho Chehab 		break;
204810a34367SMauro Carvalho Chehab 	case 0x0a:
204910a34367SMauro Carvalho Chehab 		p = "NICAM-BG";
205010a34367SMauro Carvalho Chehab 		break;
205110a34367SMauro Carvalho Chehab 	case 0x0b:
205210a34367SMauro Carvalho Chehab 		p = "NICAM-DK";
205310a34367SMauro Carvalho Chehab 		break;
205410a34367SMauro Carvalho Chehab 	case 0x0c:
205510a34367SMauro Carvalho Chehab 		p = "NICAM-I";
205610a34367SMauro Carvalho Chehab 		break;
205710a34367SMauro Carvalho Chehab 	case 0x0d:
205810a34367SMauro Carvalho Chehab 		p = "NICAM-L";
205910a34367SMauro Carvalho Chehab 		break;
206010a34367SMauro Carvalho Chehab 	case 0x0e:
206110a34367SMauro Carvalho Chehab 		p = "FM radio";
206210a34367SMauro Carvalho Chehab 		break;
206310a34367SMauro Carvalho Chehab 	case 0x0f:
206410a34367SMauro Carvalho Chehab 		p = "automatic detection";
206510a34367SMauro Carvalho Chehab 		break;
206610a34367SMauro Carvalho Chehab 	default:
206710a34367SMauro Carvalho Chehab 		p = "undefined";
2068cb7a01acSMauro Carvalho Chehab 	}
2069cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "Configured audio standard: %s\n", p);
2070cb7a01acSMauro Carvalho Chehab 
2071cb7a01acSMauro Carvalho Chehab 	if ((audio_config >> 4) < 0xF) {
2072cb7a01acSMauro Carvalho Chehab 		switch (audio_config & 0xF) {
207310a34367SMauro Carvalho Chehab 		case 0x00:
207410a34367SMauro Carvalho Chehab 			p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)";
207510a34367SMauro Carvalho Chehab 			break;
207610a34367SMauro Carvalho Chehab 		case 0x01:
207710a34367SMauro Carvalho Chehab 			p = "MONO2 (LANGUAGE B)";
207810a34367SMauro Carvalho Chehab 			break;
207910a34367SMauro Carvalho Chehab 		case 0x02:
208010a34367SMauro Carvalho Chehab 			p = "MONO3 (STEREO forced MONO)";
208110a34367SMauro Carvalho Chehab 			break;
208210a34367SMauro Carvalho Chehab 		case 0x03:
208310a34367SMauro Carvalho Chehab 			p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)";
208410a34367SMauro Carvalho Chehab 			break;
208510a34367SMauro Carvalho Chehab 		case 0x04:
208610a34367SMauro Carvalho Chehab 			p = "STEREO";
208710a34367SMauro Carvalho Chehab 			break;
208810a34367SMauro Carvalho Chehab 		case 0x05:
208910a34367SMauro Carvalho Chehab 			p = "DUAL1 (AB)";
209010a34367SMauro Carvalho Chehab 			break;
209110a34367SMauro Carvalho Chehab 		case 0x06:
209210a34367SMauro Carvalho Chehab 			p = "DUAL2 (AC) (FM)";
209310a34367SMauro Carvalho Chehab 			break;
209410a34367SMauro Carvalho Chehab 		case 0x07:
209510a34367SMauro Carvalho Chehab 			p = "DUAL3 (BC) (FM)";
209610a34367SMauro Carvalho Chehab 			break;
209710a34367SMauro Carvalho Chehab 		case 0x08:
209810a34367SMauro Carvalho Chehab 			p = "DUAL4 (AC) (AM)";
209910a34367SMauro Carvalho Chehab 			break;
210010a34367SMauro Carvalho Chehab 		case 0x09:
210110a34367SMauro Carvalho Chehab 			p = "DUAL5 (BC) (AM)";
210210a34367SMauro Carvalho Chehab 			break;
210310a34367SMauro Carvalho Chehab 		case 0x0a:
210410a34367SMauro Carvalho Chehab 			p = "SAP";
210510a34367SMauro Carvalho Chehab 			break;
210610a34367SMauro Carvalho Chehab 		default:
210710a34367SMauro Carvalho Chehab 			p = "undefined";
2108cb7a01acSMauro Carvalho Chehab 		}
2109cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "Configured audio mode:     %s\n", p);
2110cb7a01acSMauro Carvalho Chehab 	} else {
2111cb7a01acSMauro Carvalho Chehab 		switch (audio_config & 0xF) {
211210a34367SMauro Carvalho Chehab 		case 0x00:
211310a34367SMauro Carvalho Chehab 			p = "BG";
211410a34367SMauro Carvalho Chehab 			break;
211510a34367SMauro Carvalho Chehab 		case 0x01:
211610a34367SMauro Carvalho Chehab 			p = "DK1";
211710a34367SMauro Carvalho Chehab 			break;
211810a34367SMauro Carvalho Chehab 		case 0x02:
211910a34367SMauro Carvalho Chehab 			p = "DK2";
212010a34367SMauro Carvalho Chehab 			break;
212110a34367SMauro Carvalho Chehab 		case 0x03:
212210a34367SMauro Carvalho Chehab 			p = "DK3";
212310a34367SMauro Carvalho Chehab 			break;
212410a34367SMauro Carvalho Chehab 		case 0x04:
212510a34367SMauro Carvalho Chehab 			p = "I";
212610a34367SMauro Carvalho Chehab 			break;
212710a34367SMauro Carvalho Chehab 		case 0x05:
212810a34367SMauro Carvalho Chehab 			p = "L";
212910a34367SMauro Carvalho Chehab 			break;
213010a34367SMauro Carvalho Chehab 		case 0x06:
213110a34367SMauro Carvalho Chehab 			p = "BTSC";
213210a34367SMauro Carvalho Chehab 			break;
213310a34367SMauro Carvalho Chehab 		case 0x07:
213410a34367SMauro Carvalho Chehab 			p = "EIAJ";
213510a34367SMauro Carvalho Chehab 			break;
213610a34367SMauro Carvalho Chehab 		case 0x08:
213710a34367SMauro Carvalho Chehab 			p = "A2-M";
213810a34367SMauro Carvalho Chehab 			break;
213910a34367SMauro Carvalho Chehab 		case 0x09:
214010a34367SMauro Carvalho Chehab 			p = "FM Radio";
214110a34367SMauro Carvalho Chehab 			break;
214210a34367SMauro Carvalho Chehab 		case 0x0f:
214310a34367SMauro Carvalho Chehab 			p = "automatic standard and mode detection";
214410a34367SMauro Carvalho Chehab 			break;
214510a34367SMauro Carvalho Chehab 		default:
214610a34367SMauro Carvalho Chehab 			p = "undefined";
2147cb7a01acSMauro Carvalho Chehab 		}
2148cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "Configured audio system:   %s\n", p);
2149cb7a01acSMauro Carvalho Chehab 	}
2150cb7a01acSMauro Carvalho Chehab 
2151cb7a01acSMauro Carvalho Chehab 	if (aud_input) {
215210a34367SMauro Carvalho Chehab 		v4l_info(client, "Specified audio input:     Tuner (In%d)\n",
215310a34367SMauro Carvalho Chehab 			 aud_input);
2154cb7a01acSMauro Carvalho Chehab 	} else {
2155cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "Specified audio input:     External\n");
2156cb7a01acSMauro Carvalho Chehab 	}
2157cb7a01acSMauro Carvalho Chehab 
2158cb7a01acSMauro Carvalho Chehab 	switch (pref_mode & 0xf) {
215910a34367SMauro Carvalho Chehab 	case 0:
216010a34367SMauro Carvalho Chehab 		p = "mono/language A";
216110a34367SMauro Carvalho Chehab 		break;
216210a34367SMauro Carvalho Chehab 	case 1:
216310a34367SMauro Carvalho Chehab 		p = "language B";
216410a34367SMauro Carvalho Chehab 		break;
216510a34367SMauro Carvalho Chehab 	case 2:
216610a34367SMauro Carvalho Chehab 		p = "language C";
216710a34367SMauro Carvalho Chehab 		break;
216810a34367SMauro Carvalho Chehab 	case 3:
216910a34367SMauro Carvalho Chehab 		p = "analog fallback";
217010a34367SMauro Carvalho Chehab 		break;
217110a34367SMauro Carvalho Chehab 	case 4:
217210a34367SMauro Carvalho Chehab 		p = "stereo";
217310a34367SMauro Carvalho Chehab 		break;
217410a34367SMauro Carvalho Chehab 	case 5:
217510a34367SMauro Carvalho Chehab 		p = "language AC";
217610a34367SMauro Carvalho Chehab 		break;
217710a34367SMauro Carvalho Chehab 	case 6:
217810a34367SMauro Carvalho Chehab 		p = "language BC";
217910a34367SMauro Carvalho Chehab 		break;
218010a34367SMauro Carvalho Chehab 	case 7:
218110a34367SMauro Carvalho Chehab 		p = "language AB";
218210a34367SMauro Carvalho Chehab 		break;
218310a34367SMauro Carvalho Chehab 	default:
218410a34367SMauro Carvalho Chehab 		p = "undefined";
2185cb7a01acSMauro Carvalho Chehab 	}
2186cb7a01acSMauro Carvalho Chehab 	v4l_info(client, "Preferred audio mode:      %s\n", p);
2187cb7a01acSMauro Carvalho Chehab 
2188cb7a01acSMauro Carvalho Chehab 	if ((audio_config & 0xf) == 0xf) {
2189cb7a01acSMauro Carvalho Chehab 		switch ((afc0 >> 3) & 0x3) {
219010a34367SMauro Carvalho Chehab 		case 0:
219110a34367SMauro Carvalho Chehab 			p = "system DK";
219210a34367SMauro Carvalho Chehab 			break;
219310a34367SMauro Carvalho Chehab 		case 1:
219410a34367SMauro Carvalho Chehab 			p = "system L";
219510a34367SMauro Carvalho Chehab 			break;
219610a34367SMauro Carvalho Chehab 		case 2:
219710a34367SMauro Carvalho Chehab 			p = "autodetect";
219810a34367SMauro Carvalho Chehab 			break;
219910a34367SMauro Carvalho Chehab 		default:
220010a34367SMauro Carvalho Chehab 			p = "undefined";
2201cb7a01acSMauro Carvalho Chehab 		}
2202cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "Selected 65 MHz format:    %s\n", p);
2203cb7a01acSMauro Carvalho Chehab 
2204cb7a01acSMauro Carvalho Chehab 		switch (afc0 & 0x7) {
220510a34367SMauro Carvalho Chehab 		case 0:
220610a34367SMauro Carvalho Chehab 			p = "chroma";
220710a34367SMauro Carvalho Chehab 			break;
220810a34367SMauro Carvalho Chehab 		case 1:
220910a34367SMauro Carvalho Chehab 			p = "BTSC";
221010a34367SMauro Carvalho Chehab 			break;
221110a34367SMauro Carvalho Chehab 		case 2:
221210a34367SMauro Carvalho Chehab 			p = "EIAJ";
221310a34367SMauro Carvalho Chehab 			break;
221410a34367SMauro Carvalho Chehab 		case 3:
221510a34367SMauro Carvalho Chehab 			p = "A2-M";
221610a34367SMauro Carvalho Chehab 			break;
221710a34367SMauro Carvalho Chehab 		case 4:
221810a34367SMauro Carvalho Chehab 			p = "autodetect";
221910a34367SMauro Carvalho Chehab 			break;
222010a34367SMauro Carvalho Chehab 		default:
222110a34367SMauro Carvalho Chehab 			p = "undefined";
2222cb7a01acSMauro Carvalho Chehab 		}
2223cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "Selected 45 MHz format:    %s\n", p);
2224cb7a01acSMauro Carvalho Chehab 	}
2225cb7a01acSMauro Carvalho Chehab }
2226cb7a01acSMauro Carvalho Chehab 
2227e81a9076SMaciej S. Szmigiero #define CX25840_VCONFIG_OPTION(state, cfg_in, opt_msk)			\
2228e81a9076SMaciej S. Szmigiero 	do {								\
2229e81a9076SMaciej S. Szmigiero 		if ((cfg_in) & (opt_msk)) {				\
2230e81a9076SMaciej S. Szmigiero 			(state)->vid_config &= ~(opt_msk);		\
2231e81a9076SMaciej S. Szmigiero 			(state)->vid_config |= (cfg_in) & (opt_msk);	\
2232e81a9076SMaciej S. Szmigiero 		}							\
2233e81a9076SMaciej S. Szmigiero 	} while (0)
2234e81a9076SMaciej S. Szmigiero 
2235e81a9076SMaciej S. Szmigiero /* apply incoming options to the current vconfig */
cx25840_vconfig_add(struct cx25840_state * state,u32 cfg_in)2236e81a9076SMaciej S. Szmigiero static void cx25840_vconfig_add(struct cx25840_state *state, u32 cfg_in)
2237e81a9076SMaciej S. Szmigiero {
2238e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_FMT_MASK);
2239e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_RES_MASK);
2240e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VBIRAW_MASK);
2241e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_ANCDATA_MASK);
2242e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_TASKBIT_MASK);
2243e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_ACTIVE_MASK);
2244e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VALID_MASK);
2245e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_HRESETW_MASK);
2246e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_CLKGATE_MASK);
2247e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_DCMODE_MASK);
2248e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_IDID0S_MASK);
2249e81a9076SMaciej S. Szmigiero 	CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VIPCLAMP_MASK);
2250e81a9076SMaciej S. Szmigiero }
2251e81a9076SMaciej S. Szmigiero 
2252cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
2253cb7a01acSMauro Carvalho Chehab 
2254e81a9076SMaciej S. Szmigiero /*
2255e81a9076SMaciej S. Szmigiero  * Initializes the device in the generic mode.
2256e81a9076SMaciej S. Szmigiero  * For cx2584x chips also adds additional video output settings provided
2257e81a9076SMaciej S. Szmigiero  * in @val parameter (CX25840_VCONFIG_*).
2258e81a9076SMaciej S. Szmigiero  *
2259e81a9076SMaciej S. Szmigiero  * The generic mode disables some of the ivtv-related hacks in this driver.
2260e81a9076SMaciej S. Szmigiero  * For cx2584x chips it also enables setting video output configuration while
2261e81a9076SMaciej S. Szmigiero  * setting it according to datasheet defaults by default.
2262e81a9076SMaciej S. Szmigiero  */
cx25840_init(struct v4l2_subdev * sd,u32 val)2263e81a9076SMaciej S. Szmigiero static int cx25840_init(struct v4l2_subdev *sd, u32 val)
2264e81a9076SMaciej S. Szmigiero {
2265e81a9076SMaciej S. Szmigiero 	struct cx25840_state *state = to_state(sd);
2266e81a9076SMaciej S. Szmigiero 
2267e81a9076SMaciej S. Szmigiero 	state->generic_mode = true;
2268e81a9076SMaciej S. Szmigiero 
2269e81a9076SMaciej S. Szmigiero 	if (is_cx2584x(state)) {
2270e81a9076SMaciej S. Szmigiero 		/* set datasheet video output defaults */
2271e81a9076SMaciej S. Szmigiero 		state->vid_config = CX25840_VCONFIG_FMT_BT656 |
2272e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_RES_8BIT |
2273e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_VBIRAW_DISABLED |
2274e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_ANCDATA_ENABLED |
2275e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_TASKBIT_ONE |
2276e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_ACTIVE_HORIZONTAL |
2277e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_VALID_NORMAL |
2278e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_HRESETW_NORMAL |
2279e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_CLKGATE_NONE |
2280e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_DCMODE_DWORDS |
2281e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_IDID0S_NORMAL |
2282e81a9076SMaciej S. Szmigiero 				    CX25840_VCONFIG_VIPCLAMP_DISABLED;
2283e81a9076SMaciej S. Szmigiero 
2284e81a9076SMaciej S. Szmigiero 		/* add additional settings */
2285e81a9076SMaciej S. Szmigiero 		cx25840_vconfig_add(state, val);
228610a34367SMauro Carvalho Chehab 	} else {
228710a34367SMauro Carvalho Chehab 		/* TODO: generic mode needs to be developed for other chips */
2288e81a9076SMaciej S. Szmigiero 		WARN_ON(1);
228910a34367SMauro Carvalho Chehab 	}
2290e81a9076SMaciej S. Szmigiero 
2291e81a9076SMaciej S. Szmigiero 	return 0;
2292e81a9076SMaciej S. Szmigiero }
2293e81a9076SMaciej S. Szmigiero 
cx25840_reset(struct v4l2_subdev * sd,u32 val)2294ccf7a31fSMaciej S. Szmigiero static int cx25840_reset(struct v4l2_subdev *sd, u32 val)
2295cb7a01acSMauro Carvalho Chehab {
2296cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2297cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2298cb7a01acSMauro Carvalho Chehab 
2299cb7a01acSMauro Carvalho Chehab 	if (is_cx2583x(state))
2300cb7a01acSMauro Carvalho Chehab 		cx25836_initialize(client);
2301cb7a01acSMauro Carvalho Chehab 	else if (is_cx2388x(state))
2302cb7a01acSMauro Carvalho Chehab 		cx23885_initialize(client);
2303cb7a01acSMauro Carvalho Chehab 	else if (is_cx231xx(state))
2304cb7a01acSMauro Carvalho Chehab 		cx231xx_initialize(client);
2305cb7a01acSMauro Carvalho Chehab 	else
2306cb7a01acSMauro Carvalho Chehab 		cx25840_initialize(client);
2307ccf7a31fSMaciej S. Szmigiero 
2308ccf7a31fSMaciej S. Szmigiero 	state->is_initialized = 1;
2309ccf7a31fSMaciej S. Szmigiero 
2310ccf7a31fSMaciej S. Szmigiero 	return 0;
2311ccf7a31fSMaciej S. Szmigiero }
2312ccf7a31fSMaciej S. Szmigiero 
2313ccf7a31fSMaciej S. Szmigiero /*
2314ccf7a31fSMaciej S. Szmigiero  * This load_fw operation must be called to load the driver's firmware.
2315ccf7a31fSMaciej S. Szmigiero  * This will load the firmware on the first invocation (further ones are NOP).
2316ccf7a31fSMaciej S. Szmigiero  * Without this the audio standard detection will fail and you will
2317ccf7a31fSMaciej S. Szmigiero  * only get mono.
2318ccf7a31fSMaciej S. Szmigiero  * Alternatively, you can call the reset operation instead of this one.
2319ccf7a31fSMaciej S. Szmigiero  *
2320ccf7a31fSMaciej S. Szmigiero  * Since loading the firmware is often problematic when the driver is
2321ccf7a31fSMaciej S. Szmigiero  * compiled into the kernel I recommend postponing calling this function
2322ccf7a31fSMaciej S. Szmigiero  * until the first open of the video device. Another reason for
2323ccf7a31fSMaciej S. Szmigiero  * postponing it is that loading this firmware takes a long time (seconds)
2324ccf7a31fSMaciej S. Szmigiero  * due to the slow i2c bus speed. So it will speed up the boot process if
2325ccf7a31fSMaciej S. Szmigiero  * you can avoid loading the fw as long as the video device isn't used.
2326ccf7a31fSMaciej S. Szmigiero  */
cx25840_load_fw(struct v4l2_subdev * sd)2327ccf7a31fSMaciej S. Szmigiero static int cx25840_load_fw(struct v4l2_subdev *sd)
2328ccf7a31fSMaciej S. Szmigiero {
2329ccf7a31fSMaciej S. Szmigiero 	struct cx25840_state *state = to_state(sd);
2330ccf7a31fSMaciej S. Szmigiero 
2331ccf7a31fSMaciej S. Szmigiero 	if (!state->is_initialized) {
2332ccf7a31fSMaciej S. Szmigiero 		/* initialize and load firmware */
2333ccf7a31fSMaciej S. Szmigiero 		cx25840_reset(sd, 0);
2334cb7a01acSMauro Carvalho Chehab 	}
2335cb7a01acSMauro Carvalho Chehab 	return 0;
2336cb7a01acSMauro Carvalho Chehab }
2337cb7a01acSMauro Carvalho Chehab 
2338cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
cx25840_g_register(struct v4l2_subdev * sd,struct v4l2_dbg_register * reg)233910a34367SMauro Carvalho Chehab static int cx25840_g_register(struct v4l2_subdev *sd,
234010a34367SMauro Carvalho Chehab 			      struct v4l2_dbg_register *reg)
2341cb7a01acSMauro Carvalho Chehab {
2342cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2343cb7a01acSMauro Carvalho Chehab 
2344cb7a01acSMauro Carvalho Chehab 	reg->size = 1;
2345cb7a01acSMauro Carvalho Chehab 	reg->val = cx25840_read(client, reg->reg & 0x0fff);
2346cb7a01acSMauro Carvalho Chehab 	return 0;
2347cb7a01acSMauro Carvalho Chehab }
2348cb7a01acSMauro Carvalho Chehab 
cx25840_s_register(struct v4l2_subdev * sd,const struct v4l2_dbg_register * reg)234910a34367SMauro Carvalho Chehab static int cx25840_s_register(struct v4l2_subdev *sd,
235010a34367SMauro Carvalho Chehab 			      const struct v4l2_dbg_register *reg)
2351cb7a01acSMauro Carvalho Chehab {
2352cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2353cb7a01acSMauro Carvalho Chehab 
2354cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
2355cb7a01acSMauro Carvalho Chehab 	return 0;
2356cb7a01acSMauro Carvalho Chehab }
2357cb7a01acSMauro Carvalho Chehab #endif
2358cb7a01acSMauro Carvalho Chehab 
cx25840_s_audio_stream(struct v4l2_subdev * sd,int enable)2359cb7a01acSMauro Carvalho Chehab static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable)
2360cb7a01acSMauro Carvalho Chehab {
2361cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2362cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2363cb7a01acSMauro Carvalho Chehab 	u8 v;
2364cb7a01acSMauro Carvalho Chehab 
2365cb7a01acSMauro Carvalho Chehab 	if (is_cx2583x(state) || is_cx2388x(state) || is_cx231xx(state))
2366cb7a01acSMauro Carvalho Chehab 		return 0;
2367cb7a01acSMauro Carvalho Chehab 
2368cb7a01acSMauro Carvalho Chehab 	v4l_dbg(1, cx25840_debug, client, "%s audio output\n",
2369cb7a01acSMauro Carvalho Chehab 		enable ? "enable" : "disable");
2370cb7a01acSMauro Carvalho Chehab 
2371cb7a01acSMauro Carvalho Chehab 	if (enable) {
2372cb7a01acSMauro Carvalho Chehab 		v = cx25840_read(client, 0x115) | 0x80;
2373cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x115, v);
2374cb7a01acSMauro Carvalho Chehab 		v = cx25840_read(client, 0x116) | 0x03;
2375cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x116, v);
2376cb7a01acSMauro Carvalho Chehab 	} else {
2377cb7a01acSMauro Carvalho Chehab 		v = cx25840_read(client, 0x115) & ~(0x80);
2378cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x115, v);
2379cb7a01acSMauro Carvalho Chehab 		v = cx25840_read(client, 0x116) & ~(0x03);
2380cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x116, v);
2381cb7a01acSMauro Carvalho Chehab 	}
2382cb7a01acSMauro Carvalho Chehab 	return 0;
2383cb7a01acSMauro Carvalho Chehab }
2384cb7a01acSMauro Carvalho Chehab 
cx25840_s_stream(struct v4l2_subdev * sd,int enable)2385cb7a01acSMauro Carvalho Chehab static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
2386cb7a01acSMauro Carvalho Chehab {
2387cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2388cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2389cb7a01acSMauro Carvalho Chehab 	u8 v;
2390cb7a01acSMauro Carvalho Chehab 
2391cb7a01acSMauro Carvalho Chehab 	v4l_dbg(1, cx25840_debug, client, "%s video output\n",
2392cb7a01acSMauro Carvalho Chehab 		enable ? "enable" : "disable");
2393e69d8942SHans Verkuil 
2394e69d8942SHans Verkuil 	/*
2395e69d8942SHans Verkuil 	 * It's not clear what should be done for these devices.
2396e69d8942SHans Verkuil 	 * The original code used the same addresses as for the cx25840, but
2397e69d8942SHans Verkuil 	 * those addresses do something else entirely on the cx2388x and
2398e69d8942SHans Verkuil 	 * cx231xx. Since it never did anything in the first place, just do
2399e69d8942SHans Verkuil 	 * nothing.
2400e69d8942SHans Verkuil 	 */
2401e69d8942SHans Verkuil 	if (is_cx2388x(state) || is_cx231xx(state))
2402e69d8942SHans Verkuil 		return 0;
2403e69d8942SHans Verkuil 
2404cb7a01acSMauro Carvalho Chehab 	if (enable) {
2405cb7a01acSMauro Carvalho Chehab 		v = cx25840_read(client, 0x115) | 0x0c;
2406cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x115, v);
2407cb7a01acSMauro Carvalho Chehab 		v = cx25840_read(client, 0x116) | 0x04;
2408cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x116, v);
2409cb7a01acSMauro Carvalho Chehab 	} else {
2410cb7a01acSMauro Carvalho Chehab 		v = cx25840_read(client, 0x115) & ~(0x0c);
2411cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x115, v);
2412cb7a01acSMauro Carvalho Chehab 		v = cx25840_read(client, 0x116) & ~(0x04);
2413cb7a01acSMauro Carvalho Chehab 		cx25840_write(client, 0x116, v);
2414cb7a01acSMauro Carvalho Chehab 	}
2415cb7a01acSMauro Carvalho Chehab 	return 0;
2416cb7a01acSMauro Carvalho Chehab }
2417cb7a01acSMauro Carvalho Chehab 
2418cb7a01acSMauro Carvalho Chehab /* Query the current detected video format */
cx25840_querystd(struct v4l2_subdev * sd,v4l2_std_id * std)241960acc4abSMaciej S. Szmigiero static int cx25840_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
2420cb7a01acSMauro Carvalho Chehab {
2421cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2422cb7a01acSMauro Carvalho Chehab 
24232be730b8SColin Ian King 	static const v4l2_std_id stds[] = {
2424cb7a01acSMauro Carvalho Chehab 		/* 0000 */ V4L2_STD_UNKNOWN,
2425cb7a01acSMauro Carvalho Chehab 
2426cb7a01acSMauro Carvalho Chehab 		/* 0001 */ V4L2_STD_NTSC_M,
2427cb7a01acSMauro Carvalho Chehab 		/* 0010 */ V4L2_STD_NTSC_M_JP,
2428cb7a01acSMauro Carvalho Chehab 		/* 0011 */ V4L2_STD_NTSC_443,
2429cb7a01acSMauro Carvalho Chehab 		/* 0100 */ V4L2_STD_PAL,
2430cb7a01acSMauro Carvalho Chehab 		/* 0101 */ V4L2_STD_PAL_M,
2431cb7a01acSMauro Carvalho Chehab 		/* 0110 */ V4L2_STD_PAL_N,
2432cb7a01acSMauro Carvalho Chehab 		/* 0111 */ V4L2_STD_PAL_Nc,
2433cb7a01acSMauro Carvalho Chehab 		/* 1000 */ V4L2_STD_PAL_60,
2434cb7a01acSMauro Carvalho Chehab 
2435cb7a01acSMauro Carvalho Chehab 		/* 1001 */ V4L2_STD_UNKNOWN,
2436cb7a01acSMauro Carvalho Chehab 		/* 1010 */ V4L2_STD_UNKNOWN,
2437cb7a01acSMauro Carvalho Chehab 		/* 1011 */ V4L2_STD_UNKNOWN,
24387ff06130SMaciej S. Szmigiero 		/* 1100 */ V4L2_STD_SECAM,
24397ff06130SMaciej S. Szmigiero 		/* 1101 */ V4L2_STD_UNKNOWN,
2440cb7a01acSMauro Carvalho Chehab 		/* 1110 */ V4L2_STD_UNKNOWN,
2441cb7a01acSMauro Carvalho Chehab 		/* 1111 */ V4L2_STD_UNKNOWN
2442cb7a01acSMauro Carvalho Chehab 	};
2443cb7a01acSMauro Carvalho Chehab 
2444cb7a01acSMauro Carvalho Chehab 	u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf;
2445cb7a01acSMauro Carvalho Chehab 	*std = stds[fmt];
2446cb7a01acSMauro Carvalho Chehab 
244760acc4abSMaciej S. Szmigiero 	v4l_dbg(1, cx25840_debug, client,
244860acc4abSMaciej S. Szmigiero 		"querystd fmt = %x, v4l2_std_id = 0x%x\n",
2449cb7a01acSMauro Carvalho Chehab 		fmt, (unsigned int)stds[fmt]);
2450cb7a01acSMauro Carvalho Chehab 
2451cb7a01acSMauro Carvalho Chehab 	return 0;
2452cb7a01acSMauro Carvalho Chehab }
2453cb7a01acSMauro Carvalho Chehab 
cx25840_g_input_status(struct v4l2_subdev * sd,u32 * status)2454cb7a01acSMauro Carvalho Chehab static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status)
2455cb7a01acSMauro Carvalho Chehab {
2456cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2457cb7a01acSMauro Carvalho Chehab 
245810a34367SMauro Carvalho Chehab 	/*
245910a34367SMauro Carvalho Chehab 	 * A limited function that checks for signal status and returns
2460cb7a01acSMauro Carvalho Chehab 	 * the state.
2461cb7a01acSMauro Carvalho Chehab 	 */
2462cb7a01acSMauro Carvalho Chehab 
2463cb7a01acSMauro Carvalho Chehab 	/* Check for status of Horizontal lock (SRC lock isn't reliable) */
2464cb7a01acSMauro Carvalho Chehab 	if ((cx25840_read4(client, 0x40c) & 0x00010000) == 0)
2465cb7a01acSMauro Carvalho Chehab 		*status |= V4L2_IN_ST_NO_SIGNAL;
2466cb7a01acSMauro Carvalho Chehab 
2467cb7a01acSMauro Carvalho Chehab 	return 0;
2468cb7a01acSMauro Carvalho Chehab }
2469cb7a01acSMauro Carvalho Chehab 
cx25840_g_std(struct v4l2_subdev * sd,v4l2_std_id * std)2470763549a3SMaciej S. Szmigiero static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
2471763549a3SMaciej S. Szmigiero {
2472763549a3SMaciej S. Szmigiero 	struct cx25840_state *state = to_state(sd);
2473763549a3SMaciej S. Szmigiero 
2474763549a3SMaciej S. Szmigiero 	*std = state->std;
2475763549a3SMaciej S. Szmigiero 
2476763549a3SMaciej S. Szmigiero 	return 0;
2477763549a3SMaciej S. Szmigiero }
2478763549a3SMaciej S. Szmigiero 
cx25840_s_std(struct v4l2_subdev * sd,v4l2_std_id std)2479cb7a01acSMauro Carvalho Chehab static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
2480cb7a01acSMauro Carvalho Chehab {
2481cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2482cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2483cb7a01acSMauro Carvalho Chehab 
2484cb7a01acSMauro Carvalho Chehab 	if (state->radio == 0 && state->std == std)
2485cb7a01acSMauro Carvalho Chehab 		return 0;
2486cb7a01acSMauro Carvalho Chehab 	state->radio = 0;
2487cb7a01acSMauro Carvalho Chehab 	state->std = std;
2488cb7a01acSMauro Carvalho Chehab 	return set_v4lstd(client);
2489cb7a01acSMauro Carvalho Chehab }
2490cb7a01acSMauro Carvalho Chehab 
cx25840_s_radio(struct v4l2_subdev * sd)2491cb7a01acSMauro Carvalho Chehab static int cx25840_s_radio(struct v4l2_subdev *sd)
2492cb7a01acSMauro Carvalho Chehab {
2493cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2494cb7a01acSMauro Carvalho Chehab 
2495cb7a01acSMauro Carvalho Chehab 	state->radio = 1;
2496cb7a01acSMauro Carvalho Chehab 	return 0;
2497cb7a01acSMauro Carvalho Chehab }
2498cb7a01acSMauro Carvalho Chehab 
cx25840_s_video_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)2499cb7a01acSMauro Carvalho Chehab static int cx25840_s_video_routing(struct v4l2_subdev *sd,
2500cb7a01acSMauro Carvalho Chehab 				   u32 input, u32 output, u32 config)
2501cb7a01acSMauro Carvalho Chehab {
2502cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2503cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2504cb7a01acSMauro Carvalho Chehab 
2505cb7a01acSMauro Carvalho Chehab 	if (is_cx23888(state))
2506cb7a01acSMauro Carvalho Chehab 		cx23888_std_setup(client);
2507cb7a01acSMauro Carvalho Chehab 
2508e81a9076SMaciej S. Szmigiero 	if (is_cx2584x(state) && state->generic_mode && config) {
2509e81a9076SMaciej S. Szmigiero 		cx25840_vconfig_add(state, config);
2510e81a9076SMaciej S. Szmigiero 		cx25840_vconfig_apply(client);
2511e81a9076SMaciej S. Szmigiero 	}
2512e81a9076SMaciej S. Szmigiero 
2513cb7a01acSMauro Carvalho Chehab 	return set_input(client, input, state->aud_input);
2514cb7a01acSMauro Carvalho Chehab }
2515cb7a01acSMauro Carvalho Chehab 
cx25840_s_audio_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)2516cb7a01acSMauro Carvalho Chehab static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
2517cb7a01acSMauro Carvalho Chehab 				   u32 input, u32 output, u32 config)
2518cb7a01acSMauro Carvalho Chehab {
2519cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2520cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2521cb7a01acSMauro Carvalho Chehab 
2522cb7a01acSMauro Carvalho Chehab 	if (is_cx23888(state))
2523cb7a01acSMauro Carvalho Chehab 		cx23888_std_setup(client);
2524cb7a01acSMauro Carvalho Chehab 	return set_input(client, state->vid_input, input);
2525cb7a01acSMauro Carvalho Chehab }
2526cb7a01acSMauro Carvalho Chehab 
cx25840_s_frequency(struct v4l2_subdev * sd,const struct v4l2_frequency * freq)252710a34367SMauro Carvalho Chehab static int cx25840_s_frequency(struct v4l2_subdev *sd,
252810a34367SMauro Carvalho Chehab 			       const struct v4l2_frequency *freq)
2529cb7a01acSMauro Carvalho Chehab {
2530cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2531cb7a01acSMauro Carvalho Chehab 
2532cb7a01acSMauro Carvalho Chehab 	input_change(client);
2533cb7a01acSMauro Carvalho Chehab 	return 0;
2534cb7a01acSMauro Carvalho Chehab }
2535cb7a01acSMauro Carvalho Chehab 
cx25840_g_tuner(struct v4l2_subdev * sd,struct v4l2_tuner * vt)2536cb7a01acSMauro Carvalho Chehab static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
2537cb7a01acSMauro Carvalho Chehab {
2538cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2539cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2540cb7a01acSMauro Carvalho Chehab 	u8 vpres = cx25840_read(client, 0x40e) & 0x20;
2541cb7a01acSMauro Carvalho Chehab 	u8 mode;
2542cb7a01acSMauro Carvalho Chehab 	int val = 0;
2543cb7a01acSMauro Carvalho Chehab 
2544cb7a01acSMauro Carvalho Chehab 	if (state->radio)
2545cb7a01acSMauro Carvalho Chehab 		return 0;
2546cb7a01acSMauro Carvalho Chehab 
2547cb7a01acSMauro Carvalho Chehab 	vt->signal = vpres ? 0xffff : 0x0;
2548cb7a01acSMauro Carvalho Chehab 	if (is_cx2583x(state))
2549cb7a01acSMauro Carvalho Chehab 		return 0;
2550cb7a01acSMauro Carvalho Chehab 
255110a34367SMauro Carvalho Chehab 	vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
2552cb7a01acSMauro Carvalho Chehab 			  V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
2553cb7a01acSMauro Carvalho Chehab 
2554cb7a01acSMauro Carvalho Chehab 	mode = cx25840_read(client, 0x804);
2555cb7a01acSMauro Carvalho Chehab 
2556cb7a01acSMauro Carvalho Chehab 	/* get rxsubchans and audmode */
2557cb7a01acSMauro Carvalho Chehab 	if ((mode & 0xf) == 1)
2558cb7a01acSMauro Carvalho Chehab 		val |= V4L2_TUNER_SUB_STEREO;
2559cb7a01acSMauro Carvalho Chehab 	else
2560cb7a01acSMauro Carvalho Chehab 		val |= V4L2_TUNER_SUB_MONO;
2561cb7a01acSMauro Carvalho Chehab 
2562cb7a01acSMauro Carvalho Chehab 	if (mode == 2 || mode == 4)
2563cb7a01acSMauro Carvalho Chehab 		val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
2564cb7a01acSMauro Carvalho Chehab 
2565cb7a01acSMauro Carvalho Chehab 	if (mode & 0x10)
2566cb7a01acSMauro Carvalho Chehab 		val |= V4L2_TUNER_SUB_SAP;
2567cb7a01acSMauro Carvalho Chehab 
2568cb7a01acSMauro Carvalho Chehab 	vt->rxsubchans = val;
2569cb7a01acSMauro Carvalho Chehab 	vt->audmode = state->audmode;
2570cb7a01acSMauro Carvalho Chehab 	return 0;
2571cb7a01acSMauro Carvalho Chehab }
2572cb7a01acSMauro Carvalho Chehab 
cx25840_s_tuner(struct v4l2_subdev * sd,const struct v4l2_tuner * vt)25732f73c7c5SHans Verkuil static int cx25840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
2574cb7a01acSMauro Carvalho Chehab {
2575cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2576cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2577cb7a01acSMauro Carvalho Chehab 
2578cb7a01acSMauro Carvalho Chehab 	if (state->radio || is_cx2583x(state))
2579cb7a01acSMauro Carvalho Chehab 		return 0;
2580cb7a01acSMauro Carvalho Chehab 
2581cb7a01acSMauro Carvalho Chehab 	switch (vt->audmode) {
2582cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_MONO:
258310a34367SMauro Carvalho Chehab 		/*
258410a34367SMauro Carvalho Chehab 		 * mono      -> mono
258510a34367SMauro Carvalho Chehab 		 * stereo    -> mono
258610a34367SMauro Carvalho Chehab 		 * bilingual -> lang1
258710a34367SMauro Carvalho Chehab 		 */
2588cb7a01acSMauro Carvalho Chehab 		cx25840_and_or(client, 0x809, ~0xf, 0x00);
2589cb7a01acSMauro Carvalho Chehab 		break;
2590cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_STEREO:
2591cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1:
259210a34367SMauro Carvalho Chehab 		/*
259310a34367SMauro Carvalho Chehab 		 * mono      -> mono
259410a34367SMauro Carvalho Chehab 		 * stereo    -> stereo
259510a34367SMauro Carvalho Chehab 		 * bilingual -> lang1
259610a34367SMauro Carvalho Chehab 		 */
2597cb7a01acSMauro Carvalho Chehab 		cx25840_and_or(client, 0x809, ~0xf, 0x04);
2598cb7a01acSMauro Carvalho Chehab 		break;
2599cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG1_LANG2:
260010a34367SMauro Carvalho Chehab 		/*
260110a34367SMauro Carvalho Chehab 		 * mono      -> mono
260210a34367SMauro Carvalho Chehab 		 * stereo    -> stereo
260310a34367SMauro Carvalho Chehab 		 * bilingual -> lang1/lang2
260410a34367SMauro Carvalho Chehab 		 */
2605cb7a01acSMauro Carvalho Chehab 		cx25840_and_or(client, 0x809, ~0xf, 0x07);
2606cb7a01acSMauro Carvalho Chehab 		break;
2607cb7a01acSMauro Carvalho Chehab 	case V4L2_TUNER_MODE_LANG2:
260810a34367SMauro Carvalho Chehab 		/*
260910a34367SMauro Carvalho Chehab 		 * mono      -> mono
261010a34367SMauro Carvalho Chehab 		 * stereo    -> stereo
261110a34367SMauro Carvalho Chehab 		 * bilingual -> lang2
261210a34367SMauro Carvalho Chehab 		 */
2613cb7a01acSMauro Carvalho Chehab 		cx25840_and_or(client, 0x809, ~0xf, 0x01);
2614cb7a01acSMauro Carvalho Chehab 		break;
2615cb7a01acSMauro Carvalho Chehab 	default:
2616cb7a01acSMauro Carvalho Chehab 		return -EINVAL;
2617cb7a01acSMauro Carvalho Chehab 	}
2618cb7a01acSMauro Carvalho Chehab 	state->audmode = vt->audmode;
2619cb7a01acSMauro Carvalho Chehab 	return 0;
2620cb7a01acSMauro Carvalho Chehab }
2621cb7a01acSMauro Carvalho Chehab 
cx25840_log_status(struct v4l2_subdev * sd)2622cb7a01acSMauro Carvalho Chehab static int cx25840_log_status(struct v4l2_subdev *sd)
2623cb7a01acSMauro Carvalho Chehab {
2624cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2625cb7a01acSMauro Carvalho Chehab 	struct i2c_client *client = v4l2_get_subdevdata(sd);
2626cb7a01acSMauro Carvalho Chehab 
2627cb7a01acSMauro Carvalho Chehab 	log_video_status(client);
2628cb7a01acSMauro Carvalho Chehab 	if (!is_cx2583x(state))
2629cb7a01acSMauro Carvalho Chehab 		log_audio_status(client);
2630cb7a01acSMauro Carvalho Chehab 	cx25840_ir_log_status(sd);
2631cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
2632cb7a01acSMauro Carvalho Chehab 	return 0;
2633cb7a01acSMauro Carvalho Chehab }
2634cb7a01acSMauro Carvalho Chehab 
cx23885_irq_handler(struct v4l2_subdev * sd,u32 status,bool * handled)2635cb7a01acSMauro Carvalho Chehab static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status,
2636cb7a01acSMauro Carvalho Chehab 			       bool *handled)
2637cb7a01acSMauro Carvalho Chehab {
2638cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2639cb7a01acSMauro Carvalho Chehab 	struct i2c_client *c = v4l2_get_subdevdata(sd);
2640cb7a01acSMauro Carvalho Chehab 	u8 irq_stat, aud_stat, aud_en, ir_stat, ir_en;
2641cb7a01acSMauro Carvalho Chehab 	u32 vid_stat, aud_mc_stat;
2642cb7a01acSMauro Carvalho Chehab 	bool block_handled;
2643cb7a01acSMauro Carvalho Chehab 	int ret = 0;
2644cb7a01acSMauro Carvalho Chehab 
2645cb7a01acSMauro Carvalho Chehab 	irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
2646cb7a01acSMauro Carvalho Chehab 	v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (entry): %s %s %s\n",
2647cb7a01acSMauro Carvalho Chehab 		irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : "  ",
2648cb7a01acSMauro Carvalho Chehab 		irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : "   ",
2649cb7a01acSMauro Carvalho Chehab 		irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : "   ");
2650cb7a01acSMauro Carvalho Chehab 
2651cb7a01acSMauro Carvalho Chehab 	if ((is_cx23885(state) || is_cx23887(state))) {
2652cb7a01acSMauro Carvalho Chehab 		ir_stat = cx25840_read(c, CX25840_IR_STATS_REG);
2653cb7a01acSMauro Carvalho Chehab 		ir_en = cx25840_read(c, CX25840_IR_IRQEN_REG);
2654cb7a01acSMauro Carvalho Chehab 		v4l_dbg(2, cx25840_debug, c,
2655cb7a01acSMauro Carvalho Chehab 			"AV Core ir IRQ status: %#04x disables: %#04x\n",
2656cb7a01acSMauro Carvalho Chehab 			ir_stat, ir_en);
2657cb7a01acSMauro Carvalho Chehab 		if (irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT) {
2658cb7a01acSMauro Carvalho Chehab 			block_handled = false;
2659cb7a01acSMauro Carvalho Chehab 			ret = cx25840_ir_irq_handler(sd,
2660cb7a01acSMauro Carvalho Chehab 						     status, &block_handled);
2661cb7a01acSMauro Carvalho Chehab 			if (block_handled)
2662cb7a01acSMauro Carvalho Chehab 				*handled = true;
2663cb7a01acSMauro Carvalho Chehab 		}
2664cb7a01acSMauro Carvalho Chehab 	}
2665cb7a01acSMauro Carvalho Chehab 
2666cb7a01acSMauro Carvalho Chehab 	aud_stat = cx25840_read(c, CX25840_AUD_INT_STAT_REG);
2667cb7a01acSMauro Carvalho Chehab 	aud_en = cx25840_read(c, CX25840_AUD_INT_CTRL_REG);
2668cb7a01acSMauro Carvalho Chehab 	v4l_dbg(2, cx25840_debug, c,
2669cb7a01acSMauro Carvalho Chehab 		"AV Core audio IRQ status: %#04x disables: %#04x\n",
2670cb7a01acSMauro Carvalho Chehab 		aud_stat, aud_en);
2671cb7a01acSMauro Carvalho Chehab 	aud_mc_stat = cx25840_read4(c, CX23885_AUD_MC_INT_MASK_REG);
2672cb7a01acSMauro Carvalho Chehab 	v4l_dbg(2, cx25840_debug, c,
2673cb7a01acSMauro Carvalho Chehab 		"AV Core audio MC IRQ status: %#06x enables: %#06x\n",
2674cb7a01acSMauro Carvalho Chehab 		aud_mc_stat >> CX23885_AUD_MC_INT_STAT_SHFT,
2675cb7a01acSMauro Carvalho Chehab 		aud_mc_stat & CX23885_AUD_MC_INT_CTRL_BITS);
2676cb7a01acSMauro Carvalho Chehab 	if (irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT) {
2677cb7a01acSMauro Carvalho Chehab 		if (aud_stat) {
2678cb7a01acSMauro Carvalho Chehab 			cx25840_write(c, CX25840_AUD_INT_STAT_REG, aud_stat);
2679cb7a01acSMauro Carvalho Chehab 			*handled = true;
2680cb7a01acSMauro Carvalho Chehab 		}
2681cb7a01acSMauro Carvalho Chehab 	}
2682cb7a01acSMauro Carvalho Chehab 
2683cb7a01acSMauro Carvalho Chehab 	vid_stat = cx25840_read4(c, CX25840_VID_INT_STAT_REG);
2684cb7a01acSMauro Carvalho Chehab 	v4l_dbg(2, cx25840_debug, c,
2685cb7a01acSMauro Carvalho Chehab 		"AV Core video IRQ status: %#06x disables: %#06x\n",
2686cb7a01acSMauro Carvalho Chehab 		vid_stat & CX25840_VID_INT_STAT_BITS,
2687cb7a01acSMauro Carvalho Chehab 		vid_stat >> CX25840_VID_INT_MASK_SHFT);
2688cb7a01acSMauro Carvalho Chehab 	if (irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT) {
2689cb7a01acSMauro Carvalho Chehab 		if (vid_stat & CX25840_VID_INT_STAT_BITS) {
2690cb7a01acSMauro Carvalho Chehab 			cx25840_write4(c, CX25840_VID_INT_STAT_REG, vid_stat);
2691cb7a01acSMauro Carvalho Chehab 			*handled = true;
2692cb7a01acSMauro Carvalho Chehab 		}
2693cb7a01acSMauro Carvalho Chehab 	}
2694cb7a01acSMauro Carvalho Chehab 
2695cb7a01acSMauro Carvalho Chehab 	irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
2696cb7a01acSMauro Carvalho Chehab 	v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (exit): %s %s %s\n",
2697cb7a01acSMauro Carvalho Chehab 		irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : "  ",
2698cb7a01acSMauro Carvalho Chehab 		irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : "   ",
2699cb7a01acSMauro Carvalho Chehab 		irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : "   ");
2700cb7a01acSMauro Carvalho Chehab 
2701cb7a01acSMauro Carvalho Chehab 	return ret;
2702cb7a01acSMauro Carvalho Chehab }
2703cb7a01acSMauro Carvalho Chehab 
cx25840_irq_handler(struct v4l2_subdev * sd,u32 status,bool * handled)2704cb7a01acSMauro Carvalho Chehab static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status,
2705cb7a01acSMauro Carvalho Chehab 			       bool *handled)
2706cb7a01acSMauro Carvalho Chehab {
2707cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
2708cb7a01acSMauro Carvalho Chehab 
2709cb7a01acSMauro Carvalho Chehab 	*handled = false;
2710cb7a01acSMauro Carvalho Chehab 
2711cb7a01acSMauro Carvalho Chehab 	/* Only support the CX2388[578] AV Core for now */
2712cb7a01acSMauro Carvalho Chehab 	if (is_cx2388x(state))
2713cb7a01acSMauro Carvalho Chehab 		return cx23885_irq_handler(sd, status, handled);
2714cb7a01acSMauro Carvalho Chehab 
2715cb7a01acSMauro Carvalho Chehab 	return -ENODEV;
2716cb7a01acSMauro Carvalho Chehab }
2717cb7a01acSMauro Carvalho Chehab 
2718cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
2719cb7a01acSMauro Carvalho Chehab 
2720cb7a01acSMauro Carvalho Chehab #define DIF_PLL_FREQ_WORD	(0x300)
2721cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF01		(0x348)
2722cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF23		(0x34c)
2723cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF45		(0x350)
2724cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF67		(0x354)
2725cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF89		(0x358)
2726cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF1011	(0x35c)
2727cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF1213	(0x360)
2728cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF1415	(0x364)
2729cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF1617	(0x368)
2730cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF1819	(0x36c)
2731cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF2021	(0x370)
2732cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF2223	(0x374)
2733cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF2425	(0x378)
2734cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF2627	(0x37c)
2735cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF2829	(0x380)
2736cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF3031	(0x384)
2737cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF3233	(0x388)
2738cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF3435	(0x38c)
2739cb7a01acSMauro Carvalho Chehab #define DIF_BPF_COEFF36		(0x390)
2740cb7a01acSMauro Carvalho Chehab 
274157a3afc5SHans Verkuil static const u32 ifhz_coeffs[][19] = {
274257a3afc5SHans Verkuil 	{	// 3.0 MHz
274357a3afc5SHans Verkuil 		0x00000002, 0x00080012, 0x001e0024, 0x001bfff8,
274457a3afc5SHans Verkuil 		0xffb4ff50, 0xfed8fe68, 0xfe24fe34, 0xfebaffc7,
274557a3afc5SHans Verkuil 		0x014d031f, 0x04f0065d, 0x07010688, 0x04c901d6,
274657a3afc5SHans Verkuil 		0xfe00f9d3, 0xf600f342, 0xf235f337, 0xf64efb22,
274757a3afc5SHans Verkuil 		0x0105070f, 0x0c460fce, 0x110d0000,
274857a3afc5SHans Verkuil 	}, {	// 3.1 MHz
274957a3afc5SHans Verkuil 		0x00000001, 0x00070012, 0x00220032, 0x00370026,
275057a3afc5SHans Verkuil 		0xfff0ff91, 0xff0efe7c, 0xfe01fdcc, 0xfe0afedb,
275157a3afc5SHans Verkuil 		0x00440224, 0x0434060c, 0x0738074e, 0x06090361,
275257a3afc5SHans Verkuil 		0xff99fb39, 0xf6fef3b6, 0xf21af2a5, 0xf573fa33,
275357a3afc5SHans Verkuil 		0x0034067d, 0x0bfb0fb9, 0x110d0000,
275457a3afc5SHans Verkuil 	}, {	// 3.2 MHz
275557a3afc5SHans Verkuil 		0x00000000, 0x0004000e, 0x00200038, 0x004c004f,
275657a3afc5SHans Verkuil 		0x002fffdf, 0xff5cfeb6, 0xfe0dfd92, 0xfd7ffe03,
275757a3afc5SHans Verkuil 		0xff36010a, 0x03410575, 0x072607d2, 0x071804d5,
275857a3afc5SHans Verkuil 		0x0134fcb7, 0xf81ff451, 0xf223f22e, 0xf4a7f94b,
275957a3afc5SHans Verkuil 		0xff6405e8, 0x0bae0fa4, 0x110d0000,
276057a3afc5SHans Verkuil 	}, {	// 3.3 MHz
276157a3afc5SHans Verkuil 		0x0000ffff, 0x00000008, 0x001a0036, 0x0056006d,
276257a3afc5SHans Verkuil 		0x00670030, 0xffbdff10, 0xfe46fd8d, 0xfd25fd4f,
276357a3afc5SHans Verkuil 		0xfe35ffe0, 0x0224049f, 0x06c9080e, 0x07ef0627,
276457a3afc5SHans Verkuil 		0x02c9fe45, 0xf961f513, 0xf250f1d2, 0xf3ecf869,
276557a3afc5SHans Verkuil 		0xfe930552, 0x0b5f0f8f, 0x110d0000,
276657a3afc5SHans Verkuil 	}, {	// 3.4 MHz
276757a3afc5SHans Verkuil 		0xfffffffe, 0xfffd0001, 0x000f002c, 0x0054007d,
276857a3afc5SHans Verkuil 		0x0093007c, 0x0024ff82, 0xfea6fdbb, 0xfd03fcca,
276957a3afc5SHans Verkuil 		0xfd51feb9, 0x00eb0392, 0x06270802, 0x08880750,
277057a3afc5SHans Verkuil 		0x044dffdb, 0xfabdf5f8, 0xf2a0f193, 0xf342f78f,
277157a3afc5SHans Verkuil 		0xfdc404b9, 0x0b0e0f78, 0x110d0000,
277257a3afc5SHans Verkuil 	}, {	// 3.5 MHz
277357a3afc5SHans Verkuil 		0xfffffffd, 0xfffafff9, 0x0002001b, 0x0046007d,
277457a3afc5SHans Verkuil 		0x00ad00ba, 0x00870000, 0xff26fe1a, 0xfd1bfc7e,
277557a3afc5SHans Verkuil 		0xfc99fda4, 0xffa5025c, 0x054507ad, 0x08dd0847,
277657a3afc5SHans Verkuil 		0x05b80172, 0xfc2ef6ff, 0xf313f170, 0xf2abf6bd,
277757a3afc5SHans Verkuil 		0xfcf6041f, 0x0abc0f61, 0x110d0000,
277857a3afc5SHans Verkuil 	}, {	// 3.6 MHz
277957a3afc5SHans Verkuil 		0xfffffffd, 0xfff8fff3, 0xfff50006, 0x002f006c,
278057a3afc5SHans Verkuil 		0x00b200e3, 0x00dc007e, 0xffb9fea0, 0xfd6bfc71,
278157a3afc5SHans Verkuil 		0xfc17fcb1, 0xfe65010b, 0x042d0713, 0x08ec0906,
278257a3afc5SHans Verkuil 		0x07020302, 0xfdaff823, 0xf3a7f16a, 0xf228f5f5,
278357a3afc5SHans Verkuil 		0xfc2a0384, 0x0a670f4a, 0x110d0000,
278457a3afc5SHans Verkuil 	}, {	// 3.7 MHz
278557a3afc5SHans Verkuil 		0x0000fffd, 0xfff7ffef, 0xffe9fff1, 0x0010004d,
278657a3afc5SHans Verkuil 		0x00a100f2, 0x011a00f0, 0x0053ff44, 0xfdedfca2,
278757a3afc5SHans Verkuil 		0xfbd3fbef, 0xfd39ffae, 0x02ea0638, 0x08b50987,
278857a3afc5SHans Verkuil 		0x08230483, 0xff39f960, 0xf45bf180, 0xf1b8f537,
278957a3afc5SHans Verkuil 		0xfb6102e7, 0x0a110f32, 0x110d0000,
279057a3afc5SHans Verkuil 	}, {	// 3.8 MHz
279157a3afc5SHans Verkuil 		0x0000fffe, 0xfff9ffee, 0xffe1ffdd, 0xfff00024,
279257a3afc5SHans Verkuil 		0x007c00e5, 0x013a014a, 0x00e6fff8, 0xfe98fd0f,
279357a3afc5SHans Verkuil 		0xfbd3fb67, 0xfc32fe54, 0x01880525, 0x083909c7,
279457a3afc5SHans Verkuil 		0x091505ee, 0x00c7fab3, 0xf52df1b4, 0xf15df484,
279557a3afc5SHans Verkuil 		0xfa9b0249, 0x09ba0f19, 0x110d0000,
279657a3afc5SHans Verkuil 	}, {	// 3.9 MHz
279757a3afc5SHans Verkuil 		0x00000000, 0xfffbfff0, 0xffdeffcf, 0xffd1fff6,
279857a3afc5SHans Verkuil 		0x004800be, 0x01390184, 0x016300ac, 0xff5efdb1,
279957a3afc5SHans Verkuil 		0xfc17fb23, 0xfb5cfd0d, 0x001703e4, 0x077b09c4,
280057a3afc5SHans Verkuil 		0x09d2073c, 0x0251fc18, 0xf61cf203, 0xf118f3dc,
280157a3afc5SHans Verkuil 		0xf9d801aa, 0x09600eff, 0x110d0000,
280257a3afc5SHans Verkuil 	}, {	// 4.0 MHz
280357a3afc5SHans Verkuil 		0x00000001, 0xfffefff4, 0xffe1ffc8, 0xffbaffca,
280457a3afc5SHans Verkuil 		0x000b0082, 0x01170198, 0x01c10152, 0x0030fe7b,
280557a3afc5SHans Verkuil 		0xfc99fb24, 0xfac3fbe9, 0xfea5027f, 0x0683097f,
280657a3afc5SHans Verkuil 		0x0a560867, 0x03d2fd89, 0xf723f26f, 0xf0e8f341,
280757a3afc5SHans Verkuil 		0xf919010a, 0x09060ee5, 0x110d0000,
280857a3afc5SHans Verkuil 	}, {	// 4.1 MHz
280957a3afc5SHans Verkuil 		0x00010002, 0x0002fffb, 0xffe8ffca, 0xffacffa4,
281057a3afc5SHans Verkuil 		0xffcd0036, 0x00d70184, 0x01f601dc, 0x00ffff60,
281157a3afc5SHans Verkuil 		0xfd51fb6d, 0xfa6efaf5, 0xfd410103, 0x055708f9,
281257a3afc5SHans Verkuil 		0x0a9e0969, 0x0543ff02, 0xf842f2f5, 0xf0cef2b2,
281357a3afc5SHans Verkuil 		0xf85e006b, 0x08aa0ecb, 0x110d0000,
281457a3afc5SHans Verkuil 	}, {	// 4.2 MHz
281557a3afc5SHans Verkuil 		0x00010003, 0x00050003, 0xfff3ffd3, 0xffaaff8b,
281657a3afc5SHans Verkuil 		0xff95ffe5, 0x0080014a, 0x01fe023f, 0x01ba0050,
281757a3afc5SHans Verkuil 		0xfe35fbf8, 0xfa62fa3b, 0xfbf9ff7e, 0x04010836,
281857a3afc5SHans Verkuil 		0x0aa90a3d, 0x069f007f, 0xf975f395, 0xf0cbf231,
281957a3afc5SHans Verkuil 		0xf7a9ffcb, 0x084c0eaf, 0x110d0000,
282057a3afc5SHans Verkuil 	}, {	// 4.3 MHz
282157a3afc5SHans Verkuil 		0x00010003, 0x0008000a, 0x0000ffe4, 0xffb4ff81,
282257a3afc5SHans Verkuil 		0xff6aff96, 0x001c00f0, 0x01d70271, 0x0254013b,
282357a3afc5SHans Verkuil 		0xff36fcbd, 0xfa9ff9c5, 0xfadbfdfe, 0x028c073b,
282457a3afc5SHans Verkuil 		0x0a750adf, 0x07e101fa, 0xfab8f44e, 0xf0ddf1be,
282557a3afc5SHans Verkuil 		0xf6f9ff2b, 0x07ed0e94, 0x110d0000,
282657a3afc5SHans Verkuil 	}, {	// 4.4 MHz
282757a3afc5SHans Verkuil 		0x00000003, 0x0009000f, 0x000efff8, 0xffc9ff87,
282857a3afc5SHans Verkuil 		0xff52ff54, 0xffb5007e, 0x01860270, 0x02c00210,
282957a3afc5SHans Verkuil 		0x0044fdb2, 0xfb22f997, 0xf9f2fc90, 0x0102060f,
283057a3afc5SHans Verkuil 		0x0a050b4c, 0x0902036e, 0xfc0af51e, 0xf106f15a,
283157a3afc5SHans Verkuil 		0xf64efe8b, 0x078d0e77, 0x110d0000,
283257a3afc5SHans Verkuil 	}, {	// 4.5 MHz
283357a3afc5SHans Verkuil 		0x00000002, 0x00080012, 0x0019000e, 0xffe5ff9e,
283457a3afc5SHans Verkuil 		0xff4fff25, 0xff560000, 0x0112023b, 0x02f702c0,
283557a3afc5SHans Verkuil 		0x014dfec8, 0xfbe5f9b3, 0xf947fb41, 0xff7004b9,
283657a3afc5SHans Verkuil 		0x095a0b81, 0x0a0004d8, 0xfd65f603, 0xf144f104,
283757a3afc5SHans Verkuil 		0xf5aafdec, 0x072b0e5a, 0x110d0000,
283857a3afc5SHans Verkuil 	}, {	// 4.6 MHz
283957a3afc5SHans Verkuil 		0x00000001, 0x00060012, 0x00200022, 0x0005ffc1,
284057a3afc5SHans Verkuil 		0xff61ff10, 0xff09ff82, 0x008601d7, 0x02f50340,
284157a3afc5SHans Verkuil 		0x0241fff0, 0xfcddfa19, 0xf8e2fa1e, 0xfde30343,
284257a3afc5SHans Verkuil 		0x08790b7f, 0x0ad50631, 0xfec7f6fc, 0xf198f0bd,
284357a3afc5SHans Verkuil 		0xf50dfd4e, 0x06c90e3d, 0x110d0000,
284457a3afc5SHans Verkuil 	}, {	// 4.7 MHz
284557a3afc5SHans Verkuil 		0x0000ffff, 0x0003000f, 0x00220030, 0x0025ffed,
284657a3afc5SHans Verkuil 		0xff87ff15, 0xfed6ff10, 0xffed014c, 0x02b90386,
284757a3afc5SHans Verkuil 		0x03110119, 0xfdfefac4, 0xf8c6f92f, 0xfc6701b7,
284857a3afc5SHans Verkuil 		0x07670b44, 0x0b7e0776, 0x002df807, 0xf200f086,
284957a3afc5SHans Verkuil 		0xf477fcb1, 0x06650e1e, 0x110d0000,
285057a3afc5SHans Verkuil 	}, {	// 4.8 MHz
285157a3afc5SHans Verkuil 		0xfffffffe, 0xffff0009, 0x001e0038, 0x003f001b,
285257a3afc5SHans Verkuil 		0xffbcff36, 0xfec2feb6, 0xff5600a5, 0x0248038d,
285357a3afc5SHans Verkuil 		0x03b00232, 0xff39fbab, 0xf8f4f87f, 0xfb060020,
285457a3afc5SHans Verkuil 		0x062a0ad2, 0x0bf908a3, 0x0192f922, 0xf27df05e,
285557a3afc5SHans Verkuil 		0xf3e8fc14, 0x06000e00, 0x110d0000,
285657a3afc5SHans Verkuil 	}, {	// 4.9 MHz
285757a3afc5SHans Verkuil 		0xfffffffd, 0xfffc0002, 0x00160037, 0x00510046,
285857a3afc5SHans Verkuil 		0xfff9ff6d, 0xfed0fe7c, 0xfecefff0, 0x01aa0356,
285957a3afc5SHans Verkuil 		0x0413032b, 0x007ffcc5, 0xf96cf812, 0xf9cefe87,
286057a3afc5SHans Verkuil 		0x04c90a2c, 0x0c4309b4, 0x02f3fa4a, 0xf30ef046,
286157a3afc5SHans Verkuil 		0xf361fb7a, 0x059b0de0, 0x110d0000,
286257a3afc5SHans Verkuil 	}, {	// 5.0 MHz
286357a3afc5SHans Verkuil 		0xfffffffd, 0xfff9fffa, 0x000a002d, 0x00570067,
286457a3afc5SHans Verkuil 		0x0037ffb5, 0xfefffe68, 0xfe62ff3d, 0x00ec02e3,
286557a3afc5SHans Verkuil 		0x043503f6, 0x01befe05, 0xfa27f7ee, 0xf8c6fcf8,
286657a3afc5SHans Verkuil 		0x034c0954, 0x0c5c0aa4, 0x044cfb7e, 0xf3b1f03f,
286757a3afc5SHans Verkuil 		0xf2e2fae1, 0x05340dc0, 0x110d0000,
286857a3afc5SHans Verkuil 	}, {	// 5.1 MHz
286957a3afc5SHans Verkuil 		0x0000fffd, 0xfff8fff4, 0xfffd001e, 0x0051007b,
287057a3afc5SHans Verkuil 		0x006e0006, 0xff48fe7c, 0xfe1bfe9a, 0x001d023e,
287157a3afc5SHans Verkuil 		0x04130488, 0x02e6ff5b, 0xfb1ef812, 0xf7f7fb7f,
287257a3afc5SHans Verkuil 		0x01bc084e, 0x0c430b72, 0x059afcba, 0xf467f046,
287357a3afc5SHans Verkuil 		0xf26cfa4a, 0x04cd0da0, 0x110d0000,
287457a3afc5SHans Verkuil 	}, {	// 5.2 MHz
287557a3afc5SHans Verkuil 		0x0000fffe, 0xfff8ffef, 0xfff00009, 0x003f007f,
287657a3afc5SHans Verkuil 		0x00980056, 0xffa5feb6, 0xfe00fe15, 0xff4b0170,
287757a3afc5SHans Verkuil 		0x03b004d7, 0x03e800b9, 0xfc48f87f, 0xf768fa23,
287857a3afc5SHans Verkuil 		0x0022071f, 0x0bf90c1b, 0x06dafdfd, 0xf52df05e,
287957a3afc5SHans Verkuil 		0xf1fef9b5, 0x04640d7f, 0x110d0000,
288057a3afc5SHans Verkuil 	}, {	// 5.3 MHz
288157a3afc5SHans Verkuil 		0x0000ffff, 0xfff9ffee, 0xffe6fff3, 0x00250072,
288257a3afc5SHans Verkuil 		0x00af009c, 0x000cff10, 0xfe13fdb8, 0xfe870089,
288357a3afc5SHans Verkuil 		0x031104e1, 0x04b8020f, 0xfd98f92f, 0xf71df8f0,
288457a3afc5SHans Verkuil 		0xfe8805ce, 0x0b7e0c9c, 0x0808ff44, 0xf603f086,
288557a3afc5SHans Verkuil 		0xf19af922, 0x03fb0d5e, 0x110d0000,
288657a3afc5SHans Verkuil 	}, {	// 5.4 MHz
288757a3afc5SHans Verkuil 		0x00000001, 0xfffcffef, 0xffe0ffe0, 0x00050056,
288857a3afc5SHans Verkuil 		0x00b000d1, 0x0071ff82, 0xfe53fd8c, 0xfddfff99,
288957a3afc5SHans Verkuil 		0x024104a3, 0x054a034d, 0xff01fa1e, 0xf717f7ed,
289057a3afc5SHans Verkuil 		0xfcf50461, 0x0ad50cf4, 0x0921008d, 0xf6e7f0bd,
289157a3afc5SHans Verkuil 		0xf13ff891, 0x03920d3b, 0x110d0000,
289257a3afc5SHans Verkuil 	}, {	// 5.5 MHz
289357a3afc5SHans Verkuil 		0x00010002, 0xfffffff3, 0xffdeffd1, 0xffe5002f,
289457a3afc5SHans Verkuil 		0x009c00ed, 0x00cb0000, 0xfebafd94, 0xfd61feb0,
289557a3afc5SHans Verkuil 		0x014d0422, 0x05970464, 0x0074fb41, 0xf759f721,
289657a3afc5SHans Verkuil 		0xfb7502de, 0x0a000d21, 0x0a2201d4, 0xf7d9f104,
289757a3afc5SHans Verkuil 		0xf0edf804, 0x03280d19, 0x110d0000,
289857a3afc5SHans Verkuil 	}, {	// 5.6 MHz
289957a3afc5SHans Verkuil 		0x00010003, 0x0003fffa, 0xffe3ffc9, 0xffc90002,
290057a3afc5SHans Verkuil 		0x007500ef, 0x010e007e, 0xff3dfdcf, 0xfd16fddd,
290157a3afc5SHans Verkuil 		0x00440365, 0x059b0548, 0x01e3fc90, 0xf7dff691,
290257a3afc5SHans Verkuil 		0xfa0f014d, 0x09020d23, 0x0b0a0318, 0xf8d7f15a,
290357a3afc5SHans Verkuil 		0xf0a5f779, 0x02bd0cf6, 0x110d0000,
290457a3afc5SHans Verkuil 	}, {	// 5.7 MHz
290557a3afc5SHans Verkuil 		0x00010003, 0x00060001, 0xffecffc9, 0xffb4ffd4,
290657a3afc5SHans Verkuil 		0x004000d5, 0x013600f0, 0xffd3fe39, 0xfd04fd31,
290757a3afc5SHans Verkuil 		0xff360277, 0x055605ef, 0x033efdfe, 0xf8a5f642,
290857a3afc5SHans Verkuil 		0xf8cbffb6, 0x07e10cfb, 0x0bd50456, 0xf9dff1be,
290957a3afc5SHans Verkuil 		0xf067f6f2, 0x02520cd2, 0x110d0000,
291057a3afc5SHans Verkuil 	}, {	// 5.8 MHz
291157a3afc5SHans Verkuil 		0x00000003, 0x00080009, 0xfff8ffd2, 0xffaaffac,
291257a3afc5SHans Verkuil 		0x000200a3, 0x013c014a, 0x006dfec9, 0xfd2bfcb7,
291357a3afc5SHans Verkuil 		0xfe350165, 0x04cb0651, 0x0477ff7e, 0xf9a5f635,
291457a3afc5SHans Verkuil 		0xf7b1fe20, 0x069f0ca8, 0x0c81058b, 0xfaf0f231,
291557a3afc5SHans Verkuil 		0xf033f66d, 0x01e60cae, 0x110d0000,
291657a3afc5SHans Verkuil 	}, {	// 5.9 MHz
291757a3afc5SHans Verkuil 		0x00000002, 0x0009000e, 0x0005ffe1, 0xffacff90,
291857a3afc5SHans Verkuil 		0xffc5005f, 0x01210184, 0x00fcff72, 0xfd8afc77,
291957a3afc5SHans Verkuil 		0xfd51003f, 0x04020669, 0x05830103, 0xfad7f66b,
292057a3afc5SHans Verkuil 		0xf6c8fc93, 0x05430c2b, 0x0d0d06b5, 0xfc08f2b2,
292157a3afc5SHans Verkuil 		0xf00af5ec, 0x017b0c89, 0x110d0000,
292257a3afc5SHans Verkuil 	}, {	// 6.0 MHz
292357a3afc5SHans Verkuil 		0x00000001, 0x00070012, 0x0012fff5, 0xffbaff82,
292457a3afc5SHans Verkuil 		0xff8e000f, 0x00e80198, 0x01750028, 0xfe18fc75,
292557a3afc5SHans Verkuil 		0xfc99ff15, 0x03050636, 0x0656027f, 0xfc32f6e2,
292657a3afc5SHans Verkuil 		0xf614fb17, 0x03d20b87, 0x0d7707d2, 0xfd26f341,
292757a3afc5SHans Verkuil 		0xefeaf56f, 0x010f0c64, 0x110d0000,
292857a3afc5SHans Verkuil 	}, {	// 6.1 MHz
292957a3afc5SHans Verkuil 		0xffff0000, 0x00050012, 0x001c000b, 0xffd1ff84,
293057a3afc5SHans Verkuil 		0xff66ffbe, 0x00960184, 0x01cd00da, 0xfeccfcb2,
293157a3afc5SHans Verkuil 		0xfc17fdf9, 0x01e005bc, 0x06e703e4, 0xfdabf798,
293257a3afc5SHans Verkuil 		0xf599f9b3, 0x02510abd, 0x0dbf08df, 0xfe48f3dc,
293357a3afc5SHans Verkuil 		0xefd5f4f6, 0x00a20c3e, 0x110d0000,
293457a3afc5SHans Verkuil 	}, {	// 6.2 MHz
293557a3afc5SHans Verkuil 		0xfffffffe, 0x0002000f, 0x0021001f, 0xfff0ff97,
293657a3afc5SHans Verkuil 		0xff50ff74, 0x0034014a, 0x01fa0179, 0xff97fd2a,
293757a3afc5SHans Verkuil 		0xfbd3fcfa, 0x00a304fe, 0x07310525, 0xff37f886,
293857a3afc5SHans Verkuil 		0xf55cf86e, 0x00c709d0, 0x0de209db, 0xff6df484,
293957a3afc5SHans Verkuil 		0xefcbf481, 0x00360c18, 0x110d0000,
294057a3afc5SHans Verkuil 	}, {	// 6.3 MHz
294157a3afc5SHans Verkuil 		0xfffffffd, 0xfffe000a, 0x0021002f, 0x0010ffb8,
294257a3afc5SHans Verkuil 		0xff50ff3b, 0xffcc00f0, 0x01fa01fa, 0x0069fdd4,
294357a3afc5SHans Verkuil 		0xfbd3fc26, 0xff5d0407, 0x07310638, 0x00c9f9a8,
294457a3afc5SHans Verkuil 		0xf55cf74e, 0xff3908c3, 0x0de20ac3, 0x0093f537,
294557a3afc5SHans Verkuil 		0xefcbf410, 0xffca0bf2, 0x110d0000,
294657a3afc5SHans Verkuil 	}, {	// 6.4 MHz
294757a3afc5SHans Verkuil 		0xfffffffd, 0xfffb0003, 0x001c0037, 0x002fffe2,
294857a3afc5SHans Verkuil 		0xff66ff17, 0xff6a007e, 0x01cd0251, 0x0134fea5,
294957a3afc5SHans Verkuil 		0xfc17fb8b, 0xfe2002e0, 0x06e70713, 0x0255faf5,
295057a3afc5SHans Verkuil 		0xf599f658, 0xfdaf0799, 0x0dbf0b96, 0x01b8f5f5,
295157a3afc5SHans Verkuil 		0xefd5f3a3, 0xff5e0bca, 0x110d0000,
295257a3afc5SHans Verkuil 	}, {	// 6.5 MHz
295357a3afc5SHans Verkuil 		0x0000fffd, 0xfff9fffb, 0x00120037, 0x00460010,
295457a3afc5SHans Verkuil 		0xff8eff0f, 0xff180000, 0x01750276, 0x01e8ff8d,
295557a3afc5SHans Verkuil 		0xfc99fb31, 0xfcfb0198, 0x065607ad, 0x03cefc64,
295657a3afc5SHans Verkuil 		0xf614f592, 0xfc2e0656, 0x0d770c52, 0x02daf6bd,
295757a3afc5SHans Verkuil 		0xefeaf33b, 0xfef10ba3, 0x110d0000,
295857a3afc5SHans Verkuil 	}, {	// 6.6 MHz
295957a3afc5SHans Verkuil 		0x0000fffe, 0xfff7fff5, 0x0005002f, 0x0054003c,
296057a3afc5SHans Verkuil 		0xffc5ff22, 0xfedfff82, 0x00fc0267, 0x0276007e,
296157a3afc5SHans Verkuil 		0xfd51fb1c, 0xfbfe003e, 0x05830802, 0x0529fdec,
296257a3afc5SHans Verkuil 		0xf6c8f4fe, 0xfabd04ff, 0x0d0d0cf6, 0x03f8f78f,
296357a3afc5SHans Verkuil 		0xf00af2d7, 0xfe850b7b, 0x110d0000,
296457a3afc5SHans Verkuil 	}, {	// 6.7 MHz
296557a3afc5SHans Verkuil 		0x0000ffff, 0xfff8fff0, 0xfff80020, 0x00560060,
296657a3afc5SHans Verkuil 		0x0002ff4e, 0xfec4ff10, 0x006d0225, 0x02d50166,
296757a3afc5SHans Verkuil 		0xfe35fb4e, 0xfb35fee1, 0x0477080e, 0x065bff82,
296857a3afc5SHans Verkuil 		0xf7b1f4a0, 0xf9610397, 0x0c810d80, 0x0510f869,
296957a3afc5SHans Verkuil 		0xf033f278, 0xfe1a0b52, 0x110d0000,
297057a3afc5SHans Verkuil 	}, {	// 6.8 MHz
297157a3afc5SHans Verkuil 		0x00010000, 0xfffaffee, 0xffec000c, 0x004c0078,
297257a3afc5SHans Verkuil 		0x0040ff8e, 0xfecafeb6, 0xffd301b6, 0x02fc0235,
297357a3afc5SHans Verkuil 		0xff36fbc5, 0xfaaafd90, 0x033e07d2, 0x075b011b,
297457a3afc5SHans Verkuil 		0xf8cbf47a, 0xf81f0224, 0x0bd50def, 0x0621f94b,
297557a3afc5SHans Verkuil 		0xf067f21e, 0xfdae0b29, 0x110d0000,
297657a3afc5SHans Verkuil 	}, {	// 6.9 MHz
297757a3afc5SHans Verkuil 		0x00010001, 0xfffdffef, 0xffe3fff6, 0x0037007f,
297857a3afc5SHans Verkuil 		0x0075ffdc, 0xfef2fe7c, 0xff3d0122, 0x02ea02dd,
297957a3afc5SHans Verkuil 		0x0044fc79, 0xfa65fc5d, 0x01e3074e, 0x082102ad,
298057a3afc5SHans Verkuil 		0xfa0ff48c, 0xf6fe00a9, 0x0b0a0e43, 0x0729fa33,
298157a3afc5SHans Verkuil 		0xf0a5f1c9, 0xfd430b00, 0x110d0000,
298257a3afc5SHans Verkuil 	}, {	// 7.0 MHz
298357a3afc5SHans Verkuil 		0x00010002, 0x0001fff3, 0xffdeffe2, 0x001b0076,
298457a3afc5SHans Verkuil 		0x009c002d, 0xff35fe68, 0xfeba0076, 0x029f0352,
298557a3afc5SHans Verkuil 		0x014dfd60, 0xfa69fb53, 0x00740688, 0x08a7042d,
298657a3afc5SHans Verkuil 		0xfb75f4d6, 0xf600ff2d, 0x0a220e7a, 0x0827fb22,
298757a3afc5SHans Verkuil 		0xf0edf17a, 0xfcd80ad6, 0x110d0000,
298857a3afc5SHans Verkuil 	}, {	// 7.1 MHz
298957a3afc5SHans Verkuil 		0x00000003, 0x0004fff9, 0xffe0ffd2, 0xfffb005e,
299057a3afc5SHans Verkuil 		0x00b0007a, 0xff8ffe7c, 0xfe53ffc1, 0x0221038c,
299157a3afc5SHans Verkuil 		0x0241fe6e, 0xfab6fa80, 0xff010587, 0x08e90590,
299257a3afc5SHans Verkuil 		0xfcf5f556, 0xf52bfdb3, 0x09210e95, 0x0919fc15,
299357a3afc5SHans Verkuil 		0xf13ff12f, 0xfc6e0aab, 0x110d0000,
299457a3afc5SHans Verkuil 	}, {	// 7.2 MHz
299557a3afc5SHans Verkuil 		0x00000003, 0x00070000, 0xffe6ffc9, 0xffdb0039,
299657a3afc5SHans Verkuil 		0x00af00b8, 0xfff4feb6, 0xfe13ff10, 0x01790388,
299757a3afc5SHans Verkuil 		0x0311ff92, 0xfb48f9ed, 0xfd980453, 0x08e306cd,
299857a3afc5SHans Verkuil 		0xfe88f60a, 0xf482fc40, 0x08080e93, 0x09fdfd0c,
299957a3afc5SHans Verkuil 		0xf19af0ea, 0xfc050a81, 0x110d0000,
300057a3afc5SHans Verkuil 	}, {	// 7.3 MHz
300157a3afc5SHans Verkuil 		0x00000002, 0x00080008, 0xfff0ffc9, 0xffc1000d,
300257a3afc5SHans Verkuil 		0x009800e2, 0x005bff10, 0xfe00fe74, 0x00b50345,
300357a3afc5SHans Verkuil 		0x03b000bc, 0xfc18f9a1, 0xfc4802f9, 0x089807dc,
300457a3afc5SHans Verkuil 		0x0022f6f0, 0xf407fada, 0x06da0e74, 0x0ad3fe06,
300557a3afc5SHans Verkuil 		0xf1fef0ab, 0xfb9c0a55, 0x110d0000,
300657a3afc5SHans Verkuil 	}, {	// 7.4 MHz
300757a3afc5SHans Verkuil 		0x00000001, 0x0008000e, 0xfffdffd0, 0xffafffdf,
300857a3afc5SHans Verkuil 		0x006e00f2, 0x00b8ff82, 0xfe1bfdf8, 0xffe302c8,
300957a3afc5SHans Verkuil 		0x041301dc, 0xfd1af99e, 0xfb1e0183, 0x080908b5,
301057a3afc5SHans Verkuil 		0x01bcf801, 0xf3bdf985, 0x059a0e38, 0x0b99ff03,
301157a3afc5SHans Verkuil 		0xf26cf071, 0xfb330a2a, 0x110d0000,
301257a3afc5SHans Verkuil 	}, {	// 7.5 MHz
301357a3afc5SHans Verkuil 		0xffff0000, 0x00070011, 0x000affdf, 0xffa9ffb5,
301457a3afc5SHans Verkuil 		0x003700e6, 0x01010000, 0xfe62fda8, 0xff140219,
301557a3afc5SHans Verkuil 		0x043502e1, 0xfe42f9e6, 0xfa270000, 0x073a0953,
301657a3afc5SHans Verkuil 		0x034cf939, 0xf3a4f845, 0x044c0de1, 0x0c4f0000,
301757a3afc5SHans Verkuil 		0xf2e2f03c, 0xfacc09fe, 0x110d0000,
301857a3afc5SHans Verkuil 	}, {	// 7.6 MHz
301957a3afc5SHans Verkuil 		0xffffffff, 0x00040012, 0x0016fff3, 0xffafff95,
302057a3afc5SHans Verkuil 		0xfff900c0, 0x0130007e, 0xfecefd89, 0xfe560146,
302157a3afc5SHans Verkuil 		0x041303bc, 0xff81fa76, 0xf96cfe7d, 0x063209b1,
302257a3afc5SHans Verkuil 		0x04c9fa93, 0xf3bdf71e, 0x02f30d6e, 0x0cf200fd,
302357a3afc5SHans Verkuil 		0xf361f00e, 0xfa6509d1, 0x110d0000,
302457a3afc5SHans Verkuil 	}, {	// 7.7 MHz
302557a3afc5SHans Verkuil 		0xfffffffe, 0x00010010, 0x001e0008, 0xffc1ff84,
302657a3afc5SHans Verkuil 		0xffbc0084, 0x013e00f0, 0xff56fd9f, 0xfdb8005c,
302757a3afc5SHans Verkuil 		0x03b00460, 0x00c7fb45, 0xf8f4fd07, 0x04fa09ce,
302857a3afc5SHans Verkuil 		0x062afc07, 0xf407f614, 0x01920ce0, 0x0d8301fa,
302957a3afc5SHans Verkuil 		0xf3e8efe5, 0xfa0009a4, 0x110d0000,
303057a3afc5SHans Verkuil 	}, {	// 7.8 MHz
303157a3afc5SHans Verkuil 		0x0000fffd, 0xfffd000b, 0x0022001d, 0xffdbff82,
303257a3afc5SHans Verkuil 		0xff870039, 0x012a014a, 0xffedfde7, 0xfd47ff6b,
303357a3afc5SHans Verkuil 		0x031104c6, 0x0202fc4c, 0xf8c6fbad, 0x039909a7,
303457a3afc5SHans Verkuil 		0x0767fd8e, 0xf482f52b, 0x002d0c39, 0x0e0002f4,
303557a3afc5SHans Verkuil 		0xf477efc2, 0xf99b0977, 0x110d0000,
303657a3afc5SHans Verkuil 	}, {	// 7.9 MHz
303757a3afc5SHans Verkuil 		0x0000fffd, 0xfffa0004, 0x0020002d, 0xfffbff91,
303857a3afc5SHans Verkuil 		0xff61ffe8, 0x00f70184, 0x0086fe5c, 0xfd0bfe85,
303957a3afc5SHans Verkuil 		0x024104e5, 0x0323fd7d, 0xf8e2fa79, 0x021d093f,
304057a3afc5SHans Verkuil 		0x0879ff22, 0xf52bf465, 0xfec70b79, 0x0e6803eb,
304157a3afc5SHans Verkuil 		0xf50defa5, 0xf937094a, 0x110d0000,
304257a3afc5SHans Verkuil 	}, {	// 8.0 MHz
304357a3afc5SHans Verkuil 		0x0000fffe, 0xfff8fffd, 0x00190036, 0x001bffaf,
304457a3afc5SHans Verkuil 		0xff4fff99, 0x00aa0198, 0x0112fef3, 0xfd09fdb9,
304557a3afc5SHans Verkuil 		0x014d04be, 0x041bfecc, 0xf947f978, 0x00900897,
304657a3afc5SHans Verkuil 		0x095a00b9, 0xf600f3c5, 0xfd650aa3, 0x0ebc04de,
304757a3afc5SHans Verkuil 		0xf5aaef8e, 0xf8d5091c, 0x110d0000,
304857a3afc5SHans Verkuil 	}, {	// 8.1 MHz
304957a3afc5SHans Verkuil 		0x0000ffff, 0xfff7fff6, 0x000e0038, 0x0037ffd7,
305057a3afc5SHans Verkuil 		0xff52ff56, 0x004b0184, 0x0186ffa1, 0xfd40fd16,
305157a3afc5SHans Verkuil 		0x00440452, 0x04de0029, 0xf9f2f8b2, 0xfefe07b5,
305257a3afc5SHans Verkuil 		0x0a05024d, 0xf6fef34d, 0xfc0a09b8, 0x0efa05cd,
305357a3afc5SHans Verkuil 		0xf64eef7d, 0xf87308ed, 0x110d0000,
305457a3afc5SHans Verkuil 	}, {	// 8.2 MHz
305557a3afc5SHans Verkuil 		0x00010000, 0xfff8fff0, 0x00000031, 0x004c0005,
305657a3afc5SHans Verkuil 		0xff6aff27, 0xffe4014a, 0x01d70057, 0xfdacfca6,
305757a3afc5SHans Verkuil 		0xff3603a7, 0x05610184, 0xfadbf82e, 0xfd74069f,
305857a3afc5SHans Verkuil 		0x0a7503d6, 0xf81ff2ff, 0xfab808b9, 0x0f2306b5,
305957a3afc5SHans Verkuil 		0xf6f9ef72, 0xf81308bf, 0x110d0000,
306057a3afc5SHans Verkuil 	}, {	// 8.3 MHz
306157a3afc5SHans Verkuil 		0x00010001, 0xfffbffee, 0xfff30022, 0x00560032,
306257a3afc5SHans Verkuil 		0xff95ff10, 0xff8000f0, 0x01fe0106, 0xfe46fc71,
306357a3afc5SHans Verkuil 		0xfe3502c7, 0x059e02ce, 0xfbf9f7f2, 0xfbff055b,
306457a3afc5SHans Verkuil 		0x0aa9054c, 0xf961f2db, 0xf97507aa, 0x0f350797,
306557a3afc5SHans Verkuil 		0xf7a9ef6d, 0xf7b40890, 0x110d0000,
306657a3afc5SHans Verkuil 	}, {	// 8.4 MHz
306757a3afc5SHans Verkuil 		0x00010002, 0xfffeffee, 0xffe8000f, 0x00540058,
306857a3afc5SHans Verkuil 		0xffcdff14, 0xff29007e, 0x01f6019e, 0xff01fc7c,
306957a3afc5SHans Verkuil 		0xfd5101bf, 0x059203f6, 0xfd41f7fe, 0xfaa903f3,
307057a3afc5SHans Verkuil 		0x0a9e06a9, 0xfabdf2e2, 0xf842068b, 0x0f320871,
307157a3afc5SHans Verkuil 		0xf85eef6e, 0xf7560860, 0x110d0000,
307257a3afc5SHans Verkuil 	}, {	// 8.5 MHz
307357a3afc5SHans Verkuil 		0x00000003, 0x0002fff2, 0xffe1fff9, 0x00460073,
307457a3afc5SHans Verkuil 		0x000bff34, 0xfee90000, 0x01c10215, 0xffd0fcc5,
307557a3afc5SHans Verkuil 		0xfc99009d, 0x053d04f1, 0xfea5f853, 0xf97d0270,
307657a3afc5SHans Verkuil 		0x0a5607e4, 0xfc2ef314, 0xf723055f, 0x0f180943,
307757a3afc5SHans Verkuil 		0xf919ef75, 0xf6fa0830, 0x110d0000,
307857a3afc5SHans Verkuil 	}, {	// 8.6 MHz
307957a3afc5SHans Verkuil 		0x00000003, 0x0005fff8, 0xffdeffe4, 0x002f007f,
308057a3afc5SHans Verkuil 		0x0048ff6b, 0xfec7ff82, 0x0163025f, 0x00a2fd47,
308157a3afc5SHans Verkuil 		0xfc17ff73, 0x04a405b2, 0x0017f8ed, 0xf88500dc,
308257a3afc5SHans Verkuil 		0x09d208f9, 0xfdaff370, 0xf61c0429, 0x0ee80a0b,
308357a3afc5SHans Verkuil 		0xf9d8ef82, 0xf6a00800, 0x110d0000,
308457a3afc5SHans Verkuil 	}, {	// 8.7 MHz
308557a3afc5SHans Verkuil 		0x00000003, 0x0007ffff, 0xffe1ffd4, 0x0010007a,
308657a3afc5SHans Verkuil 		0x007cffb2, 0xfec6ff10, 0x00e60277, 0x0168fdf9,
308757a3afc5SHans Verkuil 		0xfbd3fe50, 0x03ce0631, 0x0188f9c8, 0xf7c7ff43,
308857a3afc5SHans Verkuil 		0x091509e3, 0xff39f3f6, 0xf52d02ea, 0x0ea30ac9,
308957a3afc5SHans Verkuil 		0xfa9bef95, 0xf64607d0, 0x110d0000,
309057a3afc5SHans Verkuil 	}, {	// 8.8 MHz
309157a3afc5SHans Verkuil 		0x00000002, 0x00090007, 0xffe9ffca, 0xfff00065,
309257a3afc5SHans Verkuil 		0x00a10003, 0xfee6feb6, 0x0053025b, 0x0213fed0,
309357a3afc5SHans Verkuil 		0xfbd3fd46, 0x02c70668, 0x02eafadb, 0xf74bfdae,
309457a3afc5SHans Verkuil 		0x08230a9c, 0x00c7f4a3, 0xf45b01a6, 0x0e480b7c,
309557a3afc5SHans Verkuil 		0xfb61efae, 0xf5ef079f, 0x110d0000,
309657a3afc5SHans Verkuil 	}, {	// 8.9 MHz
309757a3afc5SHans Verkuil 		0xffff0000, 0x0008000d, 0xfff5ffc8, 0xffd10043,
309857a3afc5SHans Verkuil 		0x00b20053, 0xff24fe7c, 0xffb9020c, 0x0295ffbb,
309957a3afc5SHans Verkuil 		0xfc17fc64, 0x019b0654, 0x042dfc1c, 0xf714fc2a,
310057a3afc5SHans Verkuil 		0x07020b21, 0x0251f575, 0xf3a7005e, 0x0dd80c24,
310157a3afc5SHans Verkuil 		0xfc2aefcd, 0xf599076e, 0x110d0000,
310257a3afc5SHans Verkuil 	}, {	// 9.0 MHz
310357a3afc5SHans Verkuil 		0xffffffff, 0x00060011, 0x0002ffcf, 0xffba0018,
310457a3afc5SHans Verkuil 		0x00ad009a, 0xff79fe68, 0xff260192, 0x02e500ab,
310557a3afc5SHans Verkuil 		0xfc99fbb6, 0x005b05f7, 0x0545fd81, 0xf723fabf,
310657a3afc5SHans Verkuil 		0x05b80b70, 0x03d2f669, 0xf313ff15, 0x0d550cbf,
310757a3afc5SHans Verkuil 		0xfcf6eff2, 0xf544073d, 0x110d0000,
310857a3afc5SHans Verkuil 	}, {	// 9.1 MHz
310957a3afc5SHans Verkuil 		0xfffffffe, 0x00030012, 0x000fffdd, 0xffacffea,
311057a3afc5SHans Verkuil 		0x009300cf, 0xffdcfe7c, 0xfea600f7, 0x02fd0190,
311157a3afc5SHans Verkuil 		0xfd51fb46, 0xff150554, 0x0627fefd, 0xf778f978,
311257a3afc5SHans Verkuil 		0x044d0b87, 0x0543f77d, 0xf2a0fdcf, 0x0cbe0d4e,
311357a3afc5SHans Verkuil 		0xfdc4f01d, 0xf4f2070b, 0x110d0000,
311457a3afc5SHans Verkuil 	}, {	// 9.2 MHz
311557a3afc5SHans Verkuil 		0x0000fffd, 0x00000010, 0x001afff0, 0xffaaffbf,
311657a3afc5SHans Verkuil 		0x006700ed, 0x0043feb6, 0xfe460047, 0x02db0258,
311757a3afc5SHans Verkuil 		0xfe35fb1b, 0xfddc0473, 0x06c90082, 0xf811f85e,
311857a3afc5SHans Verkuil 		0x02c90b66, 0x069ff8ad, 0xf250fc8d, 0x0c140dcf,
311957a3afc5SHans Verkuil 		0xfe93f04d, 0xf4a106d9, 0x110d0000,
312057a3afc5SHans Verkuil 	}, {	// 9.3 MHz
312157a3afc5SHans Verkuil 		0x0000fffd, 0xfffc000c, 0x00200006, 0xffb4ff9c,
312257a3afc5SHans Verkuil 		0x002f00ef, 0x00a4ff10, 0xfe0dff92, 0x028102f7,
312357a3afc5SHans Verkuil 		0xff36fb37, 0xfcbf035e, 0x07260202, 0xf8e8f778,
312457a3afc5SHans Verkuil 		0x01340b0d, 0x07e1f9f4, 0xf223fb51, 0x0b590e42,
312557a3afc5SHans Verkuil 		0xff64f083, 0xf45206a7, 0x110d0000,
312657a3afc5SHans Verkuil 	}, {	// 9.4 MHz
312757a3afc5SHans Verkuil 		0x0000fffd, 0xfff90005, 0x0022001a, 0xffc9ff86,
312857a3afc5SHans Verkuil 		0xfff000d7, 0x00f2ff82, 0xfe01fee5, 0x01f60362,
312957a3afc5SHans Verkuil 		0x0044fb99, 0xfbcc0222, 0x07380370, 0xf9f7f6cc,
313057a3afc5SHans Verkuil 		0xff990a7e, 0x0902fb50, 0xf21afa1f, 0x0a8d0ea6,
313157a3afc5SHans Verkuil 		0x0034f0bf, 0xf4050675, 0x110d0000,
313257a3afc5SHans Verkuil 	}, {	// 9.5 MHz
313357a3afc5SHans Verkuil 		0x0000fffe, 0xfff8fffe, 0x001e002b, 0xffe5ff81,
313457a3afc5SHans Verkuil 		0xffb400a5, 0x01280000, 0xfe24fe50, 0x01460390,
313557a3afc5SHans Verkuil 		0x014dfc3a, 0xfb1000ce, 0x070104bf, 0xfb37f65f,
313657a3afc5SHans Verkuil 		0xfe0009bc, 0x0a00fcbb, 0xf235f8f8, 0x09b20efc,
313757a3afc5SHans Verkuil 		0x0105f101, 0xf3ba0642, 0x110d0000,
313857a3afc5SHans Verkuil 	}, {	// 9.6 MHz
313957a3afc5SHans Verkuil 		0x0001ffff, 0xfff8fff7, 0x00150036, 0x0005ff8c,
314057a3afc5SHans Verkuil 		0xff810061, 0x013d007e, 0xfe71fddf, 0x007c0380,
314157a3afc5SHans Verkuil 		0x0241fd13, 0xfa94ff70, 0x068005e2, 0xfc9bf633,
314257a3afc5SHans Verkuil 		0xfc7308ca, 0x0ad5fe30, 0xf274f7e0, 0x08c90f43,
314357a3afc5SHans Verkuil 		0x01d4f147, 0xf371060f, 0x110d0000,
314457a3afc5SHans Verkuil 	}, {	// 9.7 MHz
314557a3afc5SHans Verkuil 		0x00010001, 0xfff9fff1, 0x00090038, 0x0025ffa7,
314657a3afc5SHans Verkuil 		0xff5e0012, 0x013200f0, 0xfee3fd9b, 0xffaa0331,
314757a3afc5SHans Verkuil 		0x0311fe15, 0xfa60fe18, 0x05bd06d1, 0xfe1bf64a,
314857a3afc5SHans Verkuil 		0xfafa07ae, 0x0b7effab, 0xf2d5f6d7, 0x07d30f7a,
314957a3afc5SHans Verkuil 		0x02a3f194, 0xf32905dc, 0x110d0000,
315057a3afc5SHans Verkuil 	}, {	// 9.8 MHz
315157a3afc5SHans Verkuil 		0x00010002, 0xfffcffee, 0xfffb0032, 0x003fffcd,
315257a3afc5SHans Verkuil 		0xff4effc1, 0x0106014a, 0xff6efd8a, 0xfedd02aa,
315357a3afc5SHans Verkuil 		0x03b0ff34, 0xfa74fcd7, 0x04bf0781, 0xffaaf6a3,
315457a3afc5SHans Verkuil 		0xf99e066b, 0x0bf90128, 0xf359f5e1, 0x06d20fa2,
315557a3afc5SHans Verkuil 		0x0370f1e5, 0xf2e405a8, 0x110d0000,
315657a3afc5SHans Verkuil 	}, {	// 9.9 MHz
315757a3afc5SHans Verkuil 		0x00000003, 0xffffffee, 0xffef0024, 0x0051fffa,
315857a3afc5SHans Verkuil 		0xff54ff77, 0x00be0184, 0x0006fdad, 0xfe2701f3,
315957a3afc5SHans Verkuil 		0x0413005e, 0xfad1fbba, 0x039007ee, 0x013bf73d,
316057a3afc5SHans Verkuil 		0xf868050a, 0x0c4302a1, 0xf3fdf4fe, 0x05c70fba,
316157a3afc5SHans Verkuil 		0x043bf23c, 0xf2a10575, 0x110d0000,
316257a3afc5SHans Verkuil 	}, {	// 10.0 MHz
316357a3afc5SHans Verkuil 		0x00000003, 0x0003fff1, 0xffe50011, 0x00570027,
316457a3afc5SHans Verkuil 		0xff70ff3c, 0x00620198, 0x009efe01, 0xfd95011a,
316557a3afc5SHans Verkuil 		0x04350183, 0xfb71fad0, 0x023c0812, 0x02c3f811,
316657a3afc5SHans Verkuil 		0xf75e0390, 0x0c5c0411, 0xf4c1f432, 0x04b30fc1,
316757a3afc5SHans Verkuil 		0x0503f297, 0xf2610541, 0x110d0000,
316857a3afc5SHans Verkuil 	}, {	// 10.1 MHz
316957a3afc5SHans Verkuil 		0x00000003, 0x0006fff7, 0xffdffffc, 0x00510050,
317057a3afc5SHans Verkuil 		0xff9dff18, 0xfffc0184, 0x0128fe80, 0xfd32002e,
317157a3afc5SHans Verkuil 		0x04130292, 0xfc4dfa21, 0x00d107ee, 0x0435f91c,
317257a3afc5SHans Verkuil 		0xf6850205, 0x0c430573, 0xf5a1f37d, 0x03990fba,
317357a3afc5SHans Verkuil 		0x05c7f2f8, 0xf222050d, 0x110d0000,
317457a3afc5SHans Verkuil 	}, {	// 10.2 MHz
317557a3afc5SHans Verkuil 		0x00000002, 0x0008fffe, 0xffdfffe7, 0x003f006e,
317657a3afc5SHans Verkuil 		0xffd6ff0f, 0xff96014a, 0x0197ff1f, 0xfd05ff3e,
317757a3afc5SHans Verkuil 		0x03b0037c, 0xfd59f9b7, 0xff5d0781, 0x0585fa56,
317857a3afc5SHans Verkuil 		0xf5e4006f, 0x0bf906c4, 0xf69df2e0, 0x02790fa2,
317957a3afc5SHans Verkuil 		0x0688f35d, 0xf1e604d8, 0x110d0000,
318057a3afc5SHans Verkuil 	}, {	// 10.3 MHz
318157a3afc5SHans Verkuil 		0xffff0001, 0x00090005, 0xffe4ffd6, 0x0025007e,
318257a3afc5SHans Verkuil 		0x0014ff20, 0xff3c00f0, 0x01e1ffd0, 0xfd12fe5c,
318357a3afc5SHans Verkuil 		0x03110433, 0xfe88f996, 0xfdf106d1, 0x06aafbb7,
318457a3afc5SHans Verkuil 		0xf57efed8, 0x0b7e07ff, 0xf7b0f25e, 0x01560f7a,
318557a3afc5SHans Verkuil 		0x0745f3c7, 0xf1ac04a4, 0x110d0000,
318657a3afc5SHans Verkuil 	}, {	// 10.4 MHz
318757a3afc5SHans Verkuil 		0xffffffff, 0x0008000c, 0xffedffcb, 0x0005007d,
318857a3afc5SHans Verkuil 		0x0050ff4c, 0xfef6007e, 0x01ff0086, 0xfd58fd97,
318957a3afc5SHans Verkuil 		0x024104ad, 0xffcaf9c0, 0xfc9905e2, 0x079afd35,
319057a3afc5SHans Verkuil 		0xf555fd46, 0x0ad50920, 0xf8d9f1f6, 0x00310f43,
319157a3afc5SHans Verkuil 		0x07fdf435, 0xf174046f, 0x110d0000,
319257a3afc5SHans Verkuil 	}, {	// 10.5 MHz
319357a3afc5SHans Verkuil 		0xfffffffe, 0x00050011, 0xfffaffc8, 0xffe5006b,
319457a3afc5SHans Verkuil 		0x0082ff8c, 0xfecc0000, 0x01f00130, 0xfdd2fcfc,
319557a3afc5SHans Verkuil 		0x014d04e3, 0x010efa32, 0xfb6404bf, 0x084efec5,
319657a3afc5SHans Verkuil 		0xf569fbc2, 0x0a000a23, 0xfa15f1ab, 0xff0b0efc,
319757a3afc5SHans Verkuil 		0x08b0f4a7, 0xf13f043a, 0x110d0000,
319857a3afc5SHans Verkuil 	}, {	// 10.6 MHz
319957a3afc5SHans Verkuil 		0x0000fffd, 0x00020012, 0x0007ffcd, 0xffc9004c,
320057a3afc5SHans Verkuil 		0x00a4ffd9, 0xfec3ff82, 0x01b401c1, 0xfe76fc97,
320157a3afc5SHans Verkuil 		0x004404d2, 0x0245fae8, 0xfa5f0370, 0x08c1005f,
320257a3afc5SHans Verkuil 		0xf5bcfa52, 0x09020b04, 0xfb60f17b, 0xfde70ea6,
320357a3afc5SHans Verkuil 		0x095df51e, 0xf10c0405, 0x110d0000,
320457a3afc5SHans Verkuil 	}, {	// 10.7 MHz
320557a3afc5SHans Verkuil 		0x0000fffd, 0xffff0011, 0x0014ffdb, 0xffb40023,
320657a3afc5SHans Verkuil 		0x00b2002a, 0xfedbff10, 0x0150022d, 0xff38fc6f,
320757a3afc5SHans Verkuil 		0xff36047b, 0x035efbda, 0xf9940202, 0x08ee01f5,
320857a3afc5SHans Verkuil 		0xf649f8fe, 0x07e10bc2, 0xfcb6f169, 0xfcc60e42,
320957a3afc5SHans Verkuil 		0x0a04f599, 0xf0db03d0, 0x110d0000,
321057a3afc5SHans Verkuil 	}, {	// 10.8 MHz
321157a3afc5SHans Verkuil 		0x0000fffd, 0xfffb000d, 0x001dffed, 0xffaafff5,
321257a3afc5SHans Verkuil 		0x00aa0077, 0xff13feb6, 0x00ce026b, 0x000afc85,
321357a3afc5SHans Verkuil 		0xfe3503e3, 0x044cfcfb, 0xf90c0082, 0x08d5037f,
321457a3afc5SHans Verkuil 		0xf710f7cc, 0x069f0c59, 0xfe16f173, 0xfbaa0dcf,
321557a3afc5SHans Verkuil 		0x0aa5f617, 0xf0ad039b, 0x110d0000,
321657a3afc5SHans Verkuil 	}, {	// 10.9 MHz
321757a3afc5SHans Verkuil 		0x0000fffe, 0xfff90006, 0x00210003, 0xffacffc8,
321857a3afc5SHans Verkuil 		0x008e00b6, 0xff63fe7c, 0x003a0275, 0x00dafcda,
321957a3afc5SHans Verkuil 		0xfd510313, 0x0501fe40, 0xf8cbfefd, 0x087604f0,
322057a3afc5SHans Verkuil 		0xf80af6c2, 0x05430cc8, 0xff7af19a, 0xfa940d4e,
322157a3afc5SHans Verkuil 		0x0b3ff699, 0xf0810365, 0x110d0000,
322257a3afc5SHans Verkuil 	}, {	// 11.0 MHz
322357a3afc5SHans Verkuil 		0x0001ffff, 0xfff8ffff, 0x00210018, 0xffbaffa3,
322457a3afc5SHans Verkuil 		0x006000e1, 0xffc4fe68, 0xffa0024b, 0x019afd66,
322557a3afc5SHans Verkuil 		0xfc990216, 0x0575ff99, 0xf8d4fd81, 0x07d40640,
322657a3afc5SHans Verkuil 		0xf932f5e6, 0x03d20d0d, 0x00dff1de, 0xf9860cbf,
322757a3afc5SHans Verkuil 		0x0bd1f71e, 0xf058032f, 0x110d0000,
322857a3afc5SHans Verkuil 	}, {	// 11.1 MHz
322957a3afc5SHans Verkuil 		0x00010000, 0xfff8fff8, 0x001b0029, 0xffd1ff8a,
323057a3afc5SHans Verkuil 		0x002600f2, 0x002cfe7c, 0xff0f01f0, 0x023bfe20,
323157a3afc5SHans Verkuil 		0xfc1700fa, 0x05a200f7, 0xf927fc1c, 0x06f40765,
323257a3afc5SHans Verkuil 		0xfa82f53b, 0x02510d27, 0x0243f23d, 0xf8810c24,
323357a3afc5SHans Verkuil 		0x0c5cf7a7, 0xf03102fa, 0x110d0000,
323457a3afc5SHans Verkuil 	}, {	// 11.2 MHz
323557a3afc5SHans Verkuil 		0x00010002, 0xfffafff2, 0x00110035, 0xfff0ff81,
323657a3afc5SHans Verkuil 		0xffe700e7, 0x008ffeb6, 0xfe94016d, 0x02b0fefb,
323757a3afc5SHans Verkuil 		0xfbd3ffd1, 0x05850249, 0xf9c1fadb, 0x05de0858,
323857a3afc5SHans Verkuil 		0xfbf2f4c4, 0x00c70d17, 0x03a0f2b8, 0xf7870b7c,
323957a3afc5SHans Verkuil 		0x0cdff833, 0xf00d02c4, 0x110d0000,
324057a3afc5SHans Verkuil 	}, {	// 11.3 MHz
324157a3afc5SHans Verkuil 		0x00000003, 0xfffdffee, 0x00040038, 0x0010ff88,
324257a3afc5SHans Verkuil 		0xffac00c2, 0x00e2ff10, 0xfe3900cb, 0x02f1ffe9,
324357a3afc5SHans Verkuil 		0xfbd3feaa, 0x05210381, 0xfa9cf9c8, 0x04990912,
324457a3afc5SHans Verkuil 		0xfd7af484, 0xff390cdb, 0x04f4f34d, 0xf69a0ac9,
324557a3afc5SHans Verkuil 		0x0d5af8c1, 0xefec028e, 0x110d0000,
324657a3afc5SHans Verkuil 	}, {	// 11.4 MHz
324757a3afc5SHans Verkuil 		0x00000003, 0x0000ffee, 0xfff60033, 0x002fff9f,
324857a3afc5SHans Verkuil 		0xff7b0087, 0x011eff82, 0xfe080018, 0x02f900d8,
324957a3afc5SHans Verkuil 		0xfc17fd96, 0x04790490, 0xfbadf8ed, 0x032f098e,
325057a3afc5SHans Verkuil 		0xff10f47d, 0xfdaf0c75, 0x063cf3fc, 0xf5ba0a0b,
325157a3afc5SHans Verkuil 		0x0dccf952, 0xefcd0258, 0x110d0000,
325257a3afc5SHans Verkuil 	}, {	// 11.5 MHz
325357a3afc5SHans Verkuil 		0x00000003, 0x0004fff1, 0xffea0026, 0x0046ffc3,
325457a3afc5SHans Verkuil 		0xff5a003c, 0x013b0000, 0xfe04ff63, 0x02c801b8,
325557a3afc5SHans Verkuil 		0xfc99fca6, 0x0397056a, 0xfcecf853, 0x01ad09c9,
325657a3afc5SHans Verkuil 		0x00acf4ad, 0xfc2e0be7, 0x0773f4c2, 0xf4e90943,
325757a3afc5SHans Verkuil 		0x0e35f9e6, 0xefb10221, 0x110d0000,
325857a3afc5SHans Verkuil 	}, {	// 11.6 MHz
325957a3afc5SHans Verkuil 		0x00000002, 0x0007fff6, 0xffe20014, 0x0054ffee,
326057a3afc5SHans Verkuil 		0xff4effeb, 0x0137007e, 0xfe2efebb, 0x0260027a,
326157a3afc5SHans Verkuil 		0xfd51fbe6, 0x02870605, 0xfe4af7fe, 0x001d09c1,
326257a3afc5SHans Verkuil 		0x0243f515, 0xfabd0b32, 0x0897f59e, 0xf4280871,
326357a3afc5SHans Verkuil 		0x0e95fa7c, 0xef9701eb, 0x110d0000,
326457a3afc5SHans Verkuil 	}, {	// 11.7 MHz
326557a3afc5SHans Verkuil 		0xffff0001, 0x0008fffd, 0xffdeffff, 0x0056001d,
326657a3afc5SHans Verkuil 		0xff57ff9c, 0x011300f0, 0xfe82fe2e, 0x01ca0310,
326757a3afc5SHans Verkuil 		0xfe35fb62, 0x0155065a, 0xffbaf7f2, 0xfe8c0977,
326857a3afc5SHans Verkuil 		0x03cef5b2, 0xf9610a58, 0x09a5f68f, 0xf3790797,
326957a3afc5SHans Verkuil 		0x0eebfb14, 0xef8001b5, 0x110d0000,
327057a3afc5SHans Verkuil 	}, {	// 11.8 MHz
327157a3afc5SHans Verkuil 		0xffff0000, 0x00080004, 0xffe0ffe9, 0x004c0047,
327257a3afc5SHans Verkuil 		0xff75ff58, 0x00d1014a, 0xfef9fdc8, 0x0111036f,
327357a3afc5SHans Verkuil 		0xff36fb21, 0x00120665, 0x012df82e, 0xfd0708ec,
327457a3afc5SHans Verkuil 		0x0542f682, 0xf81f095c, 0x0a9af792, 0xf2db06b5,
327557a3afc5SHans Verkuil 		0x0f38fbad, 0xef6c017e, 0x110d0000,
327657a3afc5SHans Verkuil 	}, {	// 11.9 MHz
327757a3afc5SHans Verkuil 		0xffffffff, 0x0007000b, 0xffe7ffd8, 0x00370068,
327857a3afc5SHans Verkuil 		0xffa4ff28, 0x00790184, 0xff87fd91, 0x00430392,
327957a3afc5SHans Verkuil 		0x0044fb26, 0xfece0626, 0x0294f8b2, 0xfb990825,
328057a3afc5SHans Verkuil 		0x0698f77f, 0xf6fe0842, 0x0b73f8a7, 0xf25105cd,
328157a3afc5SHans Verkuil 		0x0f7bfc48, 0xef5a0148, 0x110d0000,
328257a3afc5SHans Verkuil 	}, {	// 12.0 MHz
328357a3afc5SHans Verkuil 		0x0000fffe, 0x00050010, 0xfff2ffcc, 0x001b007b,
328457a3afc5SHans Verkuil 		0xffdfff10, 0x00140198, 0x0020fd8e, 0xff710375,
328557a3afc5SHans Verkuil 		0x014dfb73, 0xfd9a059f, 0x03e0f978, 0xfa4e0726,
328657a3afc5SHans Verkuil 		0x07c8f8a7, 0xf600070c, 0x0c2ff9c9, 0xf1db04de,
328757a3afc5SHans Verkuil 		0x0fb4fce5, 0xef4b0111, 0x110d0000,
328857a3afc5SHans Verkuil 	}, {	// 12.1 MHz
328957a3afc5SHans Verkuil 		0x0000fffd, 0x00010012, 0xffffffc8, 0xfffb007e,
329057a3afc5SHans Verkuil 		0x001dff14, 0xffad0184, 0x00b7fdbe, 0xfea9031b,
329157a3afc5SHans Verkuil 		0x0241fc01, 0xfc8504d6, 0x0504fa79, 0xf93005f6,
329257a3afc5SHans Verkuil 		0x08caf9f2, 0xf52b05c0, 0x0ccbfaf9, 0xf17903eb,
329357a3afc5SHans Verkuil 		0x0fe3fd83, 0xef3f00db, 0x110d0000,
329457a3afc5SHans Verkuil 	}, {	// 12.2 MHz
329557a3afc5SHans Verkuil 		0x0000fffd, 0xfffe0011, 0x000cffcc, 0xffdb0071,
329657a3afc5SHans Verkuil 		0x0058ff32, 0xff4f014a, 0x013cfe1f, 0xfdfb028a,
329757a3afc5SHans Verkuil 		0x0311fcc9, 0xfb9d03d6, 0x05f4fbad, 0xf848049d,
329857a3afc5SHans Verkuil 		0x0999fb5b, 0xf4820461, 0x0d46fc32, 0xf12d02f4,
329957a3afc5SHans Verkuil 		0x1007fe21, 0xef3600a4, 0x110d0000,
330057a3afc5SHans Verkuil 	}, {	// 12.3 MHz
330157a3afc5SHans Verkuil 		0x0000fffe, 0xfffa000e, 0x0017ffd9, 0xffc10055,
330257a3afc5SHans Verkuil 		0x0088ff68, 0xff0400f0, 0x01a6fea7, 0xfd7501cc,
330357a3afc5SHans Verkuil 		0x03b0fdc0, 0xfaef02a8, 0x06a7fd07, 0xf79d0326,
330457a3afc5SHans Verkuil 		0x0a31fcda, 0xf40702f3, 0x0d9ffd72, 0xf0f601fa,
330557a3afc5SHans Verkuil 		0x1021fec0, 0xef2f006d, 0x110d0000,
330657a3afc5SHans Verkuil 	}, {	// 12.4 MHz
330757a3afc5SHans Verkuil 		0x0001ffff, 0xfff80007, 0x001fffeb, 0xffaf002d,
330857a3afc5SHans Verkuil 		0x00a8ffb0, 0xfed3007e, 0x01e9ff4c, 0xfd2000ee,
330957a3afc5SHans Verkuil 		0x0413fed8, 0xfa82015c, 0x0715fe7d, 0xf7340198,
331057a3afc5SHans Verkuil 		0x0a8dfe69, 0xf3bd017c, 0x0dd5feb8, 0xf0d500fd,
331157a3afc5SHans Verkuil 		0x1031ff60, 0xef2b0037, 0x110d0000,
331257a3afc5SHans Verkuil 	}, {	// 12.5 MHz
331357a3afc5SHans Verkuil 		0x00010000, 0xfff70000, 0x00220000, 0xffa90000,
331457a3afc5SHans Verkuil 		0x00b30000, 0xfec20000, 0x02000000, 0xfd030000,
331557a3afc5SHans Verkuil 		0x04350000, 0xfa5e0000, 0x073b0000, 0xf7110000,
331657a3afc5SHans Verkuil 		0x0aac0000, 0xf3a40000, 0x0de70000, 0xf0c90000,
331757a3afc5SHans Verkuil 		0x10360000, 0xef290000, 0x110d0000,
331857a3afc5SHans Verkuil 	}, {	// 12.6 MHz
331957a3afc5SHans Verkuil 		0x00010001, 0xfff8fff9, 0x001f0015, 0xffafffd3,
332057a3afc5SHans Verkuil 		0x00a80050, 0xfed3ff82, 0x01e900b4, 0xfd20ff12,
332157a3afc5SHans Verkuil 		0x04130128, 0xfa82fea4, 0x07150183, 0xf734fe68,
332257a3afc5SHans Verkuil 		0x0a8d0197, 0xf3bdfe84, 0x0dd50148, 0xf0d5ff03,
332357a3afc5SHans Verkuil 		0x103100a0, 0xef2bffc9, 0x110d0000,
332457a3afc5SHans Verkuil 	}, {	// 12.7 MHz
332557a3afc5SHans Verkuil 		0x00000002, 0xfffafff2, 0x00170027, 0xffc1ffab,
332657a3afc5SHans Verkuil 		0x00880098, 0xff04ff10, 0x01a60159, 0xfd75fe34,
332757a3afc5SHans Verkuil 		0x03b00240, 0xfaeffd58, 0x06a702f9, 0xf79dfcda,
332857a3afc5SHans Verkuil 		0x0a310326, 0xf407fd0d, 0x0d9f028e, 0xf0f6fe06,
332957a3afc5SHans Verkuil 		0x10210140, 0xef2fff93, 0x110d0000,
333057a3afc5SHans Verkuil 	}, {	// 12.8 MHz
333157a3afc5SHans Verkuil 		0x00000003, 0xfffeffef, 0x000c0034, 0xffdbff8f,
333257a3afc5SHans Verkuil 		0x005800ce, 0xff4ffeb6, 0x013c01e1, 0xfdfbfd76,
333357a3afc5SHans Verkuil 		0x03110337, 0xfb9dfc2a, 0x05f40453, 0xf848fb63,
333457a3afc5SHans Verkuil 		0x099904a5, 0xf482fb9f, 0x0d4603ce, 0xf12dfd0c,
333557a3afc5SHans Verkuil 		0x100701df, 0xef36ff5c, 0x110d0000,
333657a3afc5SHans Verkuil 	}, {	// 12.9 MHz
333757a3afc5SHans Verkuil 		0x00000003, 0x0001ffee, 0xffff0038, 0xfffbff82,
333857a3afc5SHans Verkuil 		0x001d00ec, 0xffadfe7c, 0x00b70242, 0xfea9fce5,
333957a3afc5SHans Verkuil 		0x024103ff, 0xfc85fb2a, 0x05040587, 0xf930fa0a,
334057a3afc5SHans Verkuil 		0x08ca060e, 0xf52bfa40, 0x0ccb0507, 0xf179fc15,
334157a3afc5SHans Verkuil 		0x0fe3027d, 0xef3fff25, 0x110d0000,
334257a3afc5SHans Verkuil 	}, {	// 13.0 MHz
334357a3afc5SHans Verkuil 		0x00000002, 0x0005fff0, 0xfff20034, 0x001bff85,
334457a3afc5SHans Verkuil 		0xffdf00f0, 0x0014fe68, 0x00200272, 0xff71fc8b,
334557a3afc5SHans Verkuil 		0x014d048d, 0xfd9afa61, 0x03e00688, 0xfa4ef8da,
334657a3afc5SHans Verkuil 		0x07c80759, 0xf600f8f4, 0x0c2f0637, 0xf1dbfb22,
334757a3afc5SHans Verkuil 		0x0fb4031b, 0xef4bfeef, 0x110d0000,
334857a3afc5SHans Verkuil 	}, {	// 13.1 MHz
334957a3afc5SHans Verkuil 		0xffff0001, 0x0007fff5, 0xffe70028, 0x0037ff98,
335057a3afc5SHans Verkuil 		0xffa400d8, 0x0079fe7c, 0xff87026f, 0x0043fc6e,
335157a3afc5SHans Verkuil 		0x004404da, 0xfecef9da, 0x0294074e, 0xfb99f7db,
335257a3afc5SHans Verkuil 		0x06980881, 0xf6fef7be, 0x0b730759, 0xf251fa33,
335357a3afc5SHans Verkuil 		0x0f7b03b8, 0xef5afeb8, 0x110d0000,
335457a3afc5SHans Verkuil 	}, {	// 13.2 MHz
335557a3afc5SHans Verkuil 		0xffff0000, 0x0008fffc, 0xffe00017, 0x004cffb9,
335657a3afc5SHans Verkuil 		0xff7500a8, 0x00d1feb6, 0xfef90238, 0x0111fc91,
335757a3afc5SHans Verkuil 		0xff3604df, 0x0012f99b, 0x012d07d2, 0xfd07f714,
335857a3afc5SHans Verkuil 		0x0542097e, 0xf81ff6a4, 0x0a9a086e, 0xf2dbf94b,
335957a3afc5SHans Verkuil 		0x0f380453, 0xef6cfe82, 0x110d0000,
336057a3afc5SHans Verkuil 	}, {	// 13.3 MHz
336157a3afc5SHans Verkuil 		0xffffffff, 0x00080003, 0xffde0001, 0x0056ffe3,
336257a3afc5SHans Verkuil 		0xff570064, 0x0113ff10, 0xfe8201d2, 0x01cafcf0,
336357a3afc5SHans Verkuil 		0xfe35049e, 0x0155f9a6, 0xffba080e, 0xfe8cf689,
336457a3afc5SHans Verkuil 		0x03ce0a4e, 0xf961f5a8, 0x09a50971, 0xf379f869,
336557a3afc5SHans Verkuil 		0x0eeb04ec, 0xef80fe4b, 0x110d0000,
336657a3afc5SHans Verkuil 	}, {	// 13.4 MHz
336757a3afc5SHans Verkuil 		0x0000fffe, 0x0007000a, 0xffe2ffec, 0x00540012,
336857a3afc5SHans Verkuil 		0xff4e0015, 0x0137ff82, 0xfe2e0145, 0x0260fd86,
336957a3afc5SHans Verkuil 		0xfd51041a, 0x0287f9fb, 0xfe4a0802, 0x001df63f,
337057a3afc5SHans Verkuil 		0x02430aeb, 0xfabdf4ce, 0x08970a62, 0xf428f78f,
337157a3afc5SHans Verkuil 		0x0e950584, 0xef97fe15, 0x110d0000,
337257a3afc5SHans Verkuil 	}, {	// 13.5 MHz
337357a3afc5SHans Verkuil 		0x0000fffd, 0x0004000f, 0xffeaffda, 0x0046003d,
337457a3afc5SHans Verkuil 		0xff5affc4, 0x013b0000, 0xfe04009d, 0x02c8fe48,
337557a3afc5SHans Verkuil 		0xfc99035a, 0x0397fa96, 0xfcec07ad, 0x01adf637,
337657a3afc5SHans Verkuil 		0x00ac0b53, 0xfc2ef419, 0x07730b3e, 0xf4e9f6bd,
337757a3afc5SHans Verkuil 		0x0e35061a, 0xefb1fddf, 0x110d0000,
337857a3afc5SHans Verkuil 	}, {	// 13.6 MHz
337957a3afc5SHans Verkuil 		0x0000fffd, 0x00000012, 0xfff6ffcd, 0x002f0061,
338057a3afc5SHans Verkuil 		0xff7bff79, 0x011e007e, 0xfe08ffe8, 0x02f9ff28,
338157a3afc5SHans Verkuil 		0xfc17026a, 0x0479fb70, 0xfbad0713, 0x032ff672,
338257a3afc5SHans Verkuil 		0xff100b83, 0xfdaff38b, 0x063c0c04, 0xf5baf5f5,
338357a3afc5SHans Verkuil 		0x0dcc06ae, 0xefcdfda8, 0x110d0000,
338457a3afc5SHans Verkuil 	}, {	// 13.7 MHz
338557a3afc5SHans Verkuil 		0x0000fffd, 0xfffd0012, 0x0004ffc8, 0x00100078,
338657a3afc5SHans Verkuil 		0xffacff3e, 0x00e200f0, 0xfe39ff35, 0x02f10017,
338757a3afc5SHans Verkuil 		0xfbd30156, 0x0521fc7f, 0xfa9c0638, 0x0499f6ee,
338857a3afc5SHans Verkuil 		0xfd7a0b7c, 0xff39f325, 0x04f40cb3, 0xf69af537,
338957a3afc5SHans Verkuil 		0x0d5a073f, 0xefecfd72, 0x110d0000,
339057a3afc5SHans Verkuil 	}, {	// 13.8 MHz
339157a3afc5SHans Verkuil 		0x0001fffe, 0xfffa000e, 0x0011ffcb, 0xfff0007f,
339257a3afc5SHans Verkuil 		0xffe7ff19, 0x008f014a, 0xfe94fe93, 0x02b00105,
339357a3afc5SHans Verkuil 		0xfbd3002f, 0x0585fdb7, 0xf9c10525, 0x05def7a8,
339457a3afc5SHans Verkuil 		0xfbf20b3c, 0x00c7f2e9, 0x03a00d48, 0xf787f484,
339557a3afc5SHans Verkuil 		0x0cdf07cd, 0xf00dfd3c, 0x110d0000,
339657a3afc5SHans Verkuil 	}, {	// 13.9 MHz
339757a3afc5SHans Verkuil 		0x00010000, 0xfff80008, 0x001bffd7, 0xffd10076,
339857a3afc5SHans Verkuil 		0x0026ff0e, 0x002c0184, 0xff0ffe10, 0x023b01e0,
339957a3afc5SHans Verkuil 		0xfc17ff06, 0x05a2ff09, 0xf92703e4, 0x06f4f89b,
340057a3afc5SHans Verkuil 		0xfa820ac5, 0x0251f2d9, 0x02430dc3, 0xf881f3dc,
340157a3afc5SHans Verkuil 		0x0c5c0859, 0xf031fd06, 0x110d0000,
340257a3afc5SHans Verkuil 	}, {	// 14.0 MHz
340357a3afc5SHans Verkuil 		0x00010001, 0xfff80001, 0x0021ffe8, 0xffba005d,
340457a3afc5SHans Verkuil 		0x0060ff1f, 0xffc40198, 0xffa0fdb5, 0x019a029a,
340557a3afc5SHans Verkuil 		0xfc99fdea, 0x05750067, 0xf8d4027f, 0x07d4f9c0,
340657a3afc5SHans Verkuil 		0xf9320a1a, 0x03d2f2f3, 0x00df0e22, 0xf986f341,
340757a3afc5SHans Verkuil 		0x0bd108e2, 0xf058fcd1, 0x110d0000,
340857a3afc5SHans Verkuil 	}, {	// 14.1 MHz
340957a3afc5SHans Verkuil 		0x00000002, 0xfff9fffa, 0x0021fffd, 0xffac0038,
341057a3afc5SHans Verkuil 		0x008eff4a, 0xff630184, 0x003afd8b, 0x00da0326,
341157a3afc5SHans Verkuil 		0xfd51fced, 0x050101c0, 0xf8cb0103, 0x0876fb10,
341257a3afc5SHans Verkuil 		0xf80a093e, 0x0543f338, 0xff7a0e66, 0xfa94f2b2,
341357a3afc5SHans Verkuil 		0x0b3f0967, 0xf081fc9b, 0x110d0000,
341457a3afc5SHans Verkuil 	}, {	// 14.2 MHz
341557a3afc5SHans Verkuil 		0x00000003, 0xfffbfff3, 0x001d0013, 0xffaa000b,
341657a3afc5SHans Verkuil 		0x00aaff89, 0xff13014a, 0x00cefd95, 0x000a037b,
341757a3afc5SHans Verkuil 		0xfe35fc1d, 0x044c0305, 0xf90cff7e, 0x08d5fc81,
341857a3afc5SHans Verkuil 		0xf7100834, 0x069ff3a7, 0xfe160e8d, 0xfbaaf231,
341957a3afc5SHans Verkuil 		0x0aa509e9, 0xf0adfc65, 0x110d0000,
342057a3afc5SHans Verkuil 	}, {	// 14.3 MHz
342157a3afc5SHans Verkuil 		0x00000003, 0xffffffef, 0x00140025, 0xffb4ffdd,
342257a3afc5SHans Verkuil 		0x00b2ffd6, 0xfedb00f0, 0x0150fdd3, 0xff380391,
342357a3afc5SHans Verkuil 		0xff36fb85, 0x035e0426, 0xf994fdfe, 0x08eefe0b,
342457a3afc5SHans Verkuil 		0xf6490702, 0x07e1f43e, 0xfcb60e97, 0xfcc6f1be,
342557a3afc5SHans Verkuil 		0x0a040a67, 0xf0dbfc30, 0x110d0000,
342657a3afc5SHans Verkuil 	}, {	// 14.4 MHz
342757a3afc5SHans Verkuil 		0x00000003, 0x0002ffee, 0x00070033, 0xffc9ffb4,
342857a3afc5SHans Verkuil 		0x00a40027, 0xfec3007e, 0x01b4fe3f, 0xfe760369,
342957a3afc5SHans Verkuil 		0x0044fb2e, 0x02450518, 0xfa5ffc90, 0x08c1ffa1,
343057a3afc5SHans Verkuil 		0xf5bc05ae, 0x0902f4fc, 0xfb600e85, 0xfde7f15a,
343157a3afc5SHans Verkuil 		0x095d0ae2, 0xf10cfbfb, 0x110d0000,
343257a3afc5SHans Verkuil 	}, {	// 14.5 MHz
343357a3afc5SHans Verkuil 		0xffff0002, 0x0005ffef, 0xfffa0038, 0xffe5ff95,
343457a3afc5SHans Verkuil 		0x00820074, 0xfecc0000, 0x01f0fed0, 0xfdd20304,
343557a3afc5SHans Verkuil 		0x014dfb1d, 0x010e05ce, 0xfb64fb41, 0x084e013b,
343657a3afc5SHans Verkuil 		0xf569043e, 0x0a00f5dd, 0xfa150e55, 0xff0bf104,
343757a3afc5SHans Verkuil 		0x08b00b59, 0xf13ffbc6, 0x110d0000,
343857a3afc5SHans Verkuil 	}, {	// 14.6 MHz
343957a3afc5SHans Verkuil 		0xffff0001, 0x0008fff4, 0xffed0035, 0x0005ff83,
344057a3afc5SHans Verkuil 		0x005000b4, 0xfef6ff82, 0x01ffff7a, 0xfd580269,
344157a3afc5SHans Verkuil 		0x0241fb53, 0xffca0640, 0xfc99fa1e, 0x079a02cb,
344257a3afc5SHans Verkuil 		0xf55502ba, 0x0ad5f6e0, 0xf8d90e0a, 0x0031f0bd,
344357a3afc5SHans Verkuil 		0x07fd0bcb, 0xf174fb91, 0x110d0000,
344457a3afc5SHans Verkuil 	}, {	// 14.7 MHz
344557a3afc5SHans Verkuil 		0xffffffff, 0x0009fffb, 0xffe4002a, 0x0025ff82,
344657a3afc5SHans Verkuil 		0x001400e0, 0xff3cff10, 0x01e10030, 0xfd1201a4,
344757a3afc5SHans Verkuil 		0x0311fbcd, 0xfe88066a, 0xfdf1f92f, 0x06aa0449,
344857a3afc5SHans Verkuil 		0xf57e0128, 0x0b7ef801, 0xf7b00da2, 0x0156f086,
344957a3afc5SHans Verkuil 		0x07450c39, 0xf1acfb5c, 0x110d0000,
345057a3afc5SHans Verkuil 	}, {	// 14.8 MHz
345157a3afc5SHans Verkuil 		0x0000fffe, 0x00080002, 0xffdf0019, 0x003fff92,
345257a3afc5SHans Verkuil 		0xffd600f1, 0xff96feb6, 0x019700e1, 0xfd0500c2,
345357a3afc5SHans Verkuil 		0x03b0fc84, 0xfd590649, 0xff5df87f, 0x058505aa,
345457a3afc5SHans Verkuil 		0xf5e4ff91, 0x0bf9f93c, 0xf69d0d20, 0x0279f05e,
345557a3afc5SHans Verkuil 		0x06880ca3, 0xf1e6fb28, 0x110d0000,
345657a3afc5SHans Verkuil 	}, {	// 14.9 MHz
345757a3afc5SHans Verkuil 		0x0000fffd, 0x00060009, 0xffdf0004, 0x0051ffb0,
345857a3afc5SHans Verkuil 		0xff9d00e8, 0xfffcfe7c, 0x01280180, 0xfd32ffd2,
345957a3afc5SHans Verkuil 		0x0413fd6e, 0xfc4d05df, 0x00d1f812, 0x043506e4,
346057a3afc5SHans Verkuil 		0xf685fdfb, 0x0c43fa8d, 0xf5a10c83, 0x0399f046,
346157a3afc5SHans Verkuil 		0x05c70d08, 0xf222faf3, 0x110d0000,
346257a3afc5SHans Verkuil 	}, {	// 15.0 MHz
346357a3afc5SHans Verkuil 		0x0000fffd, 0x0003000f, 0xffe5ffef, 0x0057ffd9,
346457a3afc5SHans Verkuil 		0xff7000c4, 0x0062fe68, 0x009e01ff, 0xfd95fee6,
346557a3afc5SHans Verkuil 		0x0435fe7d, 0xfb710530, 0x023cf7ee, 0x02c307ef,
346657a3afc5SHans Verkuil 		0xf75efc70, 0x0c5cfbef, 0xf4c10bce, 0x04b3f03f,
346757a3afc5SHans Verkuil 		0x05030d69, 0xf261fabf, 0x110d0000,
346857a3afc5SHans Verkuil 	}, {	// 15.1 MHz
346957a3afc5SHans Verkuil 		0x0000fffd, 0xffff0012, 0xffefffdc, 0x00510006,
347057a3afc5SHans Verkuil 		0xff540089, 0x00befe7c, 0x00060253, 0xfe27fe0d,
347157a3afc5SHans Verkuil 		0x0413ffa2, 0xfad10446, 0x0390f812, 0x013b08c3,
347257a3afc5SHans Verkuil 		0xf868faf6, 0x0c43fd5f, 0xf3fd0b02, 0x05c7f046,
347357a3afc5SHans Verkuil 		0x043b0dc4, 0xf2a1fa8b, 0x110d0000,
347457a3afc5SHans Verkuil 	}, {	// 15.2 MHz
347557a3afc5SHans Verkuil 		0x0001fffe, 0xfffc0012, 0xfffbffce, 0x003f0033,
347657a3afc5SHans Verkuil 		0xff4e003f, 0x0106feb6, 0xff6e0276, 0xfeddfd56,
347757a3afc5SHans Verkuil 		0x03b000cc, 0xfa740329, 0x04bff87f, 0xffaa095d,
347857a3afc5SHans Verkuil 		0xf99ef995, 0x0bf9fed8, 0xf3590a1f, 0x06d2f05e,
347957a3afc5SHans Verkuil 		0x03700e1b, 0xf2e4fa58, 0x110d0000,
348057a3afc5SHans Verkuil 	}, {	// 15.3 MHz
348157a3afc5SHans Verkuil 		0x0001ffff, 0xfff9000f, 0x0009ffc8, 0x00250059,
348257a3afc5SHans Verkuil 		0xff5effee, 0x0132ff10, 0xfee30265, 0xffaafccf,
348357a3afc5SHans Verkuil 		0x031101eb, 0xfa6001e8, 0x05bdf92f, 0xfe1b09b6,
348457a3afc5SHans Verkuil 		0xfafaf852, 0x0b7e0055, 0xf2d50929, 0x07d3f086,
348557a3afc5SHans Verkuil 		0x02a30e6c, 0xf329fa24, 0x110d0000,
348657a3afc5SHans Verkuil 	}, {	// 15.4 MHz
348757a3afc5SHans Verkuil 		0x00010001, 0xfff80009, 0x0015ffca, 0x00050074,
348857a3afc5SHans Verkuil 		0xff81ff9f, 0x013dff82, 0xfe710221, 0x007cfc80,
348957a3afc5SHans Verkuil 		0x024102ed, 0xfa940090, 0x0680fa1e, 0xfc9b09cd,
349057a3afc5SHans Verkuil 		0xfc73f736, 0x0ad501d0, 0xf2740820, 0x08c9f0bd,
349157a3afc5SHans Verkuil 		0x01d40eb9, 0xf371f9f1, 0x110d0000,
349257a3afc5SHans Verkuil 	}, {	// 15.5 MHz
349357a3afc5SHans Verkuil 		0x00000002, 0xfff80002, 0x001effd5, 0xffe5007f,
349457a3afc5SHans Verkuil 		0xffb4ff5b, 0x01280000, 0xfe2401b0, 0x0146fc70,
349557a3afc5SHans Verkuil 		0x014d03c6, 0xfb10ff32, 0x0701fb41, 0xfb3709a1,
349657a3afc5SHans Verkuil 		0xfe00f644, 0x0a000345, 0xf2350708, 0x09b2f104,
349757a3afc5SHans Verkuil 		0x01050eff, 0xf3baf9be, 0x110d0000,
349857a3afc5SHans Verkuil 	}, {	// 15.6 MHz
349957a3afc5SHans Verkuil 		0x00000003, 0xfff9fffb, 0x0022ffe6, 0xffc9007a,
350057a3afc5SHans Verkuil 		0xfff0ff29, 0x00f2007e, 0xfe01011b, 0x01f6fc9e,
350157a3afc5SHans Verkuil 		0x00440467, 0xfbccfdde, 0x0738fc90, 0xf9f70934,
350257a3afc5SHans Verkuil 		0xff99f582, 0x090204b0, 0xf21a05e1, 0x0a8df15a,
350357a3afc5SHans Verkuil 		0x00340f41, 0xf405f98b, 0x110d0000,
350457a3afc5SHans Verkuil 	}, {	// 15.7 MHz
350557a3afc5SHans Verkuil 		0x00000003, 0xfffcfff4, 0x0020fffa, 0xffb40064,
350657a3afc5SHans Verkuil 		0x002fff11, 0x00a400f0, 0xfe0d006e, 0x0281fd09,
350757a3afc5SHans Verkuil 		0xff3604c9, 0xfcbffca2, 0x0726fdfe, 0xf8e80888,
350857a3afc5SHans Verkuil 		0x0134f4f3, 0x07e1060c, 0xf22304af, 0x0b59f1be,
350957a3afc5SHans Verkuil 		0xff640f7d, 0xf452f959, 0x110d0000,
351057a3afc5SHans Verkuil 	}, {	// 15.8 MHz
351157a3afc5SHans Verkuil 		0x00000003, 0x0000fff0, 0x001a0010, 0xffaa0041,
351257a3afc5SHans Verkuil 		0x0067ff13, 0x0043014a, 0xfe46ffb9, 0x02dbfda8,
351357a3afc5SHans Verkuil 		0xfe3504e5, 0xfddcfb8d, 0x06c9ff7e, 0xf81107a2,
351457a3afc5SHans Verkuil 		0x02c9f49a, 0x069f0753, 0xf2500373, 0x0c14f231,
351557a3afc5SHans Verkuil 		0xfe930fb3, 0xf4a1f927, 0x110d0000,
351657a3afc5SHans Verkuil 	}, {	// 15.9 MHz
351757a3afc5SHans Verkuil 		0xffff0002, 0x0003ffee, 0x000f0023, 0xffac0016,
351857a3afc5SHans Verkuil 		0x0093ff31, 0xffdc0184, 0xfea6ff09, 0x02fdfe70,
351957a3afc5SHans Verkuil 		0xfd5104ba, 0xff15faac, 0x06270103, 0xf7780688,
352057a3afc5SHans Verkuil 		0x044df479, 0x05430883, 0xf2a00231, 0x0cbef2b2,
352157a3afc5SHans Verkuil 		0xfdc40fe3, 0xf4f2f8f5, 0x110d0000,
352257a3afc5SHans Verkuil 	}, {	// 16.0 MHz
352357a3afc5SHans Verkuil 		0xffff0001, 0x0006ffef, 0x00020031, 0xffbaffe8,
352457a3afc5SHans Verkuil 		0x00adff66, 0xff790198, 0xff26fe6e, 0x02e5ff55,
352557a3afc5SHans Verkuil 		0xfc99044a, 0x005bfa09, 0x0545027f, 0xf7230541,
352657a3afc5SHans Verkuil 		0x05b8f490, 0x03d20997, 0xf31300eb, 0x0d55f341,
352757a3afc5SHans Verkuil 		0xfcf6100e, 0xf544f8c3, 0x110d0000,
352857a3afc5SHans Verkuil 	}
352957a3afc5SHans Verkuil };
353057a3afc5SHans Verkuil 
cx23885_dif_setup(struct i2c_client * client,u32 ifHz)3531efe1724aSMauro Carvalho Chehab static void cx23885_dif_setup(struct i2c_client *client, u32 ifHz)
3532cb7a01acSMauro Carvalho Chehab {
3533cb7a01acSMauro Carvalho Chehab 	u64 pll_freq;
3534cb7a01acSMauro Carvalho Chehab 	u32 pll_freq_word;
353557a3afc5SHans Verkuil 	const u32 *coeffs;
3536cb7a01acSMauro Carvalho Chehab 
3537cb7a01acSMauro Carvalho Chehab 	v4l_dbg(1, cx25840_debug, client, "%s(%d)\n", __func__, ifHz);
3538cb7a01acSMauro Carvalho Chehab 
3539cb7a01acSMauro Carvalho Chehab 	/* Assuming TV */
3540cb7a01acSMauro Carvalho Chehab 	/* Calculate the PLL frequency word based on the adjusted ifHz */
3541cb7a01acSMauro Carvalho Chehab 	pll_freq = div_u64((u64)ifHz * 268435456, 50000000);
3542cb7a01acSMauro Carvalho Chehab 	pll_freq_word = (u32)pll_freq;
3543cb7a01acSMauro Carvalho Chehab 
3544cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, DIF_PLL_FREQ_WORD,  pll_freq_word);
3545cb7a01acSMauro Carvalho Chehab 
3546cb7a01acSMauro Carvalho Chehab 	/* Round down to the nearest 100KHz */
3547cb7a01acSMauro Carvalho Chehab 	ifHz = (ifHz / 100000) * 100000;
3548cb7a01acSMauro Carvalho Chehab 
3549cb7a01acSMauro Carvalho Chehab 	if (ifHz < 3000000)
3550cb7a01acSMauro Carvalho Chehab 		ifHz = 3000000;
3551cb7a01acSMauro Carvalho Chehab 
3552cb7a01acSMauro Carvalho Chehab 	if (ifHz > 16000000)
3553cb7a01acSMauro Carvalho Chehab 		ifHz = 16000000;
3554cb7a01acSMauro Carvalho Chehab 
3555cb7a01acSMauro Carvalho Chehab 	v4l_dbg(1, cx25840_debug, client, "%s(%d) again\n", __func__, ifHz);
3556cb7a01acSMauro Carvalho Chehab 
355757a3afc5SHans Verkuil 	coeffs = ifhz_coeffs[(ifHz - 3000000) / 100000];
355857a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF01, coeffs[0]);
355957a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF23, coeffs[1]);
356057a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF45, coeffs[2]);
356157a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF67, coeffs[3]);
356257a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF89, coeffs[4]);
356357a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF1011, coeffs[5]);
356457a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF1213, coeffs[6]);
356557a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF1415, coeffs[7]);
356657a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF1617, coeffs[8]);
356757a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF1819, coeffs[9]);
356857a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF2021, coeffs[10]);
356957a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF2223, coeffs[11]);
357057a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF2425, coeffs[12]);
357157a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF2627, coeffs[13]);
357257a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF2829, coeffs[14]);
357357a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF3031, coeffs[15]);
357457a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF3233, coeffs[16]);
357557a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF3435, coeffs[17]);
357657a3afc5SHans Verkuil 	cx25840_write4(client, DIF_BPF_COEFF36, coeffs[18]);
3577cb7a01acSMauro Carvalho Chehab }
3578cb7a01acSMauro Carvalho Chehab 
cx23888_std_setup(struct i2c_client * client)3579cb7a01acSMauro Carvalho Chehab static void cx23888_std_setup(struct i2c_client *client)
3580cb7a01acSMauro Carvalho Chehab {
3581cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
3582cb7a01acSMauro Carvalho Chehab 	v4l2_std_id std = state->std;
3583cb7a01acSMauro Carvalho Chehab 	u32 ifHz;
3584cb7a01acSMauro Carvalho Chehab 
3585cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x478, 0x6628021F);
3586cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x400, 0x0);
3587cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x4b4, 0x20524030);
3588cb7a01acSMauro Carvalho Chehab 	cx25840_write4(client, 0x47c, 0x010a8263);
3589cb7a01acSMauro Carvalho Chehab 
3590bfd1bbfbSHans Verkuil 	if (std & V4L2_STD_525_60) {
3591cb7a01acSMauro Carvalho Chehab 		v4l_dbg(1, cx25840_debug, client, "%s() Selecting NTSC",
3592cb7a01acSMauro Carvalho Chehab 			__func__);
3593cb7a01acSMauro Carvalho Chehab 
3594cb7a01acSMauro Carvalho Chehab 		/* Horiz / vert timing */
3595cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x428, 0x1e1e601a);
3596cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x424, 0x5b2d007a);
3597cb7a01acSMauro Carvalho Chehab 
3598cb7a01acSMauro Carvalho Chehab 		/* DIF NTSC */
3599cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x304, 0x6503bc0c);
3600cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x308, 0xbd038c85);
3601cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x30c, 0x1db4640a);
3602cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x310, 0x00008800);
3603cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x314, 0x44400400);
3604cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x32c, 0x0c800800);
3605cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x330, 0x27000100);
3606cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x334, 0x1f296e1f);
3607cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x338, 0x009f50c1);
3608cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x340, 0x1befbf06);
3609cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x344, 0x000035e8);
3610cb7a01acSMauro Carvalho Chehab 
3611cb7a01acSMauro Carvalho Chehab 		/* DIF I/F */
3612cb7a01acSMauro Carvalho Chehab 		ifHz = 5400000;
3613cb7a01acSMauro Carvalho Chehab 
3614cb7a01acSMauro Carvalho Chehab 	} else {
3615cb7a01acSMauro Carvalho Chehab 		v4l_dbg(1, cx25840_debug, client, "%s() Selecting PAL-BG",
3616cb7a01acSMauro Carvalho Chehab 			__func__);
3617cb7a01acSMauro Carvalho Chehab 
3618cb7a01acSMauro Carvalho Chehab 		/* Horiz / vert timing */
3619cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x428, 0x28244024);
3620cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x424, 0x5d2d0084);
3621cb7a01acSMauro Carvalho Chehab 
3622cb7a01acSMauro Carvalho Chehab 		/* DIF */
3623cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x304, 0x6503bc0c);
3624cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x308, 0xbd038c85);
3625cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x30c, 0x1db4640a);
3626cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x310, 0x00008800);
3627cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x314, 0x44400600);
3628cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x32c, 0x0c800800);
3629cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x330, 0x27000100);
3630cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x334, 0x213530ec);
3631cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x338, 0x00a65ba8);
3632cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x340, 0x1befbf06);
3633cb7a01acSMauro Carvalho Chehab 		cx25840_write4(client, 0x344, 0x000035e8);
3634cb7a01acSMauro Carvalho Chehab 
3635cb7a01acSMauro Carvalho Chehab 		/* DIF I/F */
3636cb7a01acSMauro Carvalho Chehab 		ifHz = 6000000;
3637cb7a01acSMauro Carvalho Chehab 	}
3638cb7a01acSMauro Carvalho Chehab 
3639cb7a01acSMauro Carvalho Chehab 	cx23885_dif_setup(client, ifHz);
3640cb7a01acSMauro Carvalho Chehab 
3641cb7a01acSMauro Carvalho Chehab 	/* Explicitly ensure the inputs are reconfigured after
3642cb7a01acSMauro Carvalho Chehab 	 * a standard change.
3643cb7a01acSMauro Carvalho Chehab 	 */
3644cb7a01acSMauro Carvalho Chehab 	set_input(client, state->vid_input, state->aud_input);
3645cb7a01acSMauro Carvalho Chehab }
3646cb7a01acSMauro Carvalho Chehab 
3647cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
3648cb7a01acSMauro Carvalho Chehab 
3649cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {
3650cb7a01acSMauro Carvalho Chehab 	.s_ctrl = cx25840_s_ctrl,
3651cb7a01acSMauro Carvalho Chehab };
3652cb7a01acSMauro Carvalho Chehab 
3653cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops cx25840_core_ops = {
3654cb7a01acSMauro Carvalho Chehab 	.log_status = cx25840_log_status,
3655cb7a01acSMauro Carvalho Chehab 	.reset = cx25840_reset,
3656e81a9076SMaciej S. Szmigiero 	/* calling the (optional) init op will turn on the generic mode */
3657e81a9076SMaciej S. Szmigiero 	.init = cx25840_init,
3658cb7a01acSMauro Carvalho Chehab 	.load_fw = cx25840_load_fw,
3659cb7a01acSMauro Carvalho Chehab 	.s_io_pin_config = common_s_io_pin_config,
3660cb7a01acSMauro Carvalho Chehab #ifdef CONFIG_VIDEO_ADV_DEBUG
3661cb7a01acSMauro Carvalho Chehab 	.g_register = cx25840_g_register,
3662cb7a01acSMauro Carvalho Chehab 	.s_register = cx25840_s_register,
3663cb7a01acSMauro Carvalho Chehab #endif
3664cb7a01acSMauro Carvalho Chehab 	.interrupt_service_routine = cx25840_irq_handler,
3665cb7a01acSMauro Carvalho Chehab };
3666cb7a01acSMauro Carvalho Chehab 
3667cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
3668cb7a01acSMauro Carvalho Chehab 	.s_frequency = cx25840_s_frequency,
3669cb7a01acSMauro Carvalho Chehab 	.s_radio = cx25840_s_radio,
3670cb7a01acSMauro Carvalho Chehab 	.g_tuner = cx25840_g_tuner,
3671cb7a01acSMauro Carvalho Chehab 	.s_tuner = cx25840_s_tuner,
3672cb7a01acSMauro Carvalho Chehab };
3673cb7a01acSMauro Carvalho Chehab 
3674cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
3675cb7a01acSMauro Carvalho Chehab 	.s_clock_freq = cx25840_s_clock_freq,
3676cb7a01acSMauro Carvalho Chehab 	.s_routing = cx25840_s_audio_routing,
3677cb7a01acSMauro Carvalho Chehab 	.s_stream = cx25840_s_audio_stream,
3678cb7a01acSMauro Carvalho Chehab };
3679cb7a01acSMauro Carvalho Chehab 
3680cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops cx25840_video_ops = {
3681763549a3SMaciej S. Szmigiero 	.g_std = cx25840_g_std,
36828774bed9SLaurent Pinchart 	.s_std = cx25840_s_std,
368360acc4abSMaciej S. Szmigiero 	.querystd = cx25840_querystd,
3684cb7a01acSMauro Carvalho Chehab 	.s_routing = cx25840_s_video_routing,
3685cb7a01acSMauro Carvalho Chehab 	.s_stream = cx25840_s_stream,
3686cb7a01acSMauro Carvalho Chehab 	.g_input_status = cx25840_g_input_status,
3687cb7a01acSMauro Carvalho Chehab };
3688cb7a01acSMauro Carvalho Chehab 
3689cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_vbi_ops cx25840_vbi_ops = {
3690cb7a01acSMauro Carvalho Chehab 	.decode_vbi_line = cx25840_decode_vbi_line,
3691cb7a01acSMauro Carvalho Chehab 	.s_raw_fmt = cx25840_s_raw_fmt,
3692cb7a01acSMauro Carvalho Chehab 	.s_sliced_fmt = cx25840_s_sliced_fmt,
3693cb7a01acSMauro Carvalho Chehab 	.g_sliced_fmt = cx25840_g_sliced_fmt,
3694cb7a01acSMauro Carvalho Chehab };
3695cb7a01acSMauro Carvalho Chehab 
36966e80c473SHans Verkuil static const struct v4l2_subdev_pad_ops cx25840_pad_ops = {
36976e80c473SHans Verkuil 	.set_fmt = cx25840_set_fmt,
36986e80c473SHans Verkuil };
36996e80c473SHans Verkuil 
3700cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops cx25840_ops = {
3701cb7a01acSMauro Carvalho Chehab 	.core = &cx25840_core_ops,
3702cb7a01acSMauro Carvalho Chehab 	.tuner = &cx25840_tuner_ops,
3703cb7a01acSMauro Carvalho Chehab 	.audio = &cx25840_audio_ops,
3704cb7a01acSMauro Carvalho Chehab 	.video = &cx25840_video_ops,
3705cb7a01acSMauro Carvalho Chehab 	.vbi = &cx25840_vbi_ops,
37066e80c473SHans Verkuil 	.pad = &cx25840_pad_ops,
3707cb7a01acSMauro Carvalho Chehab 	.ir = &cx25840_ir_ops,
3708cb7a01acSMauro Carvalho Chehab };
3709cb7a01acSMauro Carvalho Chehab 
3710cb7a01acSMauro Carvalho Chehab /* ----------------------------------------------------------------------- */
3711cb7a01acSMauro Carvalho Chehab 
get_cx2388x_ident(struct i2c_client * client)3712cb7a01acSMauro Carvalho Chehab static u32 get_cx2388x_ident(struct i2c_client *client)
3713cb7a01acSMauro Carvalho Chehab {
3714cb7a01acSMauro Carvalho Chehab 	u32 ret;
3715cb7a01acSMauro Carvalho Chehab 
3716cb7a01acSMauro Carvalho Chehab 	/* Come out of digital power down */
3717cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x000, 0);
3718cb7a01acSMauro Carvalho Chehab 
371910a34367SMauro Carvalho Chehab 	/*
372010a34367SMauro Carvalho Chehab 	 * Detecting whether the part is cx23885/7/8 is more
3721cb7a01acSMauro Carvalho Chehab 	 * difficult than it needs to be. No ID register. Instead we
3722cb7a01acSMauro Carvalho Chehab 	 * probe certain registers indicated in the datasheets to look
372310a34367SMauro Carvalho Chehab 	 * for specific defaults that differ between the silicon designs.
372410a34367SMauro Carvalho Chehab 	 */
3725cb7a01acSMauro Carvalho Chehab 
3726cb7a01acSMauro Carvalho Chehab 	/* It's either 885/7 if the IR Tx Clk Divider register exists */
3727cb7a01acSMauro Carvalho Chehab 	if (cx25840_read4(client, 0x204) & 0xffff) {
372810a34367SMauro Carvalho Chehab 		/*
372910a34367SMauro Carvalho Chehab 		 * CX23885 returns bogus repetitive byte values for the DIF,
373010a34367SMauro Carvalho Chehab 		 * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131)
373110a34367SMauro Carvalho Chehab 		 */
3732cb7a01acSMauro Carvalho Chehab 		ret = cx25840_read4(client, 0x300);
3733cb7a01acSMauro Carvalho Chehab 		if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) {
3734cb7a01acSMauro Carvalho Chehab 			/* No DIF */
373529d6a98bSHans Verkuil 			ret = CX23885_AV;
3736cb7a01acSMauro Carvalho Chehab 		} else {
373710a34367SMauro Carvalho Chehab 			/*
373810a34367SMauro Carvalho Chehab 			 * CX23887 has a broken DIF, but the registers
373910a34367SMauro Carvalho Chehab 			 * appear valid (but unused), good enough to detect.
374010a34367SMauro Carvalho Chehab 			 */
374129d6a98bSHans Verkuil 			ret = CX23887_AV;
3742cb7a01acSMauro Carvalho Chehab 		}
3743cb7a01acSMauro Carvalho Chehab 	} else if (cx25840_read4(client, 0x300) & 0x0fffffff) {
3744cb7a01acSMauro Carvalho Chehab 		/* DIF PLL Freq Word reg exists; chip must be a CX23888 */
374529d6a98bSHans Verkuil 		ret = CX23888_AV;
3746cb7a01acSMauro Carvalho Chehab 	} else {
3747cb7a01acSMauro Carvalho Chehab 		v4l_err(client, "Unable to detect h/w, assuming cx23887\n");
374829d6a98bSHans Verkuil 		ret = CX23887_AV;
3749cb7a01acSMauro Carvalho Chehab 	}
3750cb7a01acSMauro Carvalho Chehab 
3751cb7a01acSMauro Carvalho Chehab 	/* Back into digital power down */
3752cb7a01acSMauro Carvalho Chehab 	cx25840_write(client, 0x000, 2);
3753cb7a01acSMauro Carvalho Chehab 	return ret;
3754cb7a01acSMauro Carvalho Chehab }
3755cb7a01acSMauro Carvalho Chehab 
cx25840_probe(struct i2c_client * client)37563c6d4866SUwe Kleine-König static int cx25840_probe(struct i2c_client *client)
3757cb7a01acSMauro Carvalho Chehab {
3758cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state;
3759cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd;
3760cb7a01acSMauro Carvalho Chehab 	int default_volume;
376129d6a98bSHans Verkuil 	u32 id;
3762cb7a01acSMauro Carvalho Chehab 	u16 device_id;
37638cd61969SMauro Carvalho Chehab #if defined(CONFIG_MEDIA_CONTROLLER)
37648cd61969SMauro Carvalho Chehab 	int ret;
37658cd61969SMauro Carvalho Chehab #endif
3766cb7a01acSMauro Carvalho Chehab 
3767cb7a01acSMauro Carvalho Chehab 	/* Check if the adapter supports the needed features */
3768cb7a01acSMauro Carvalho Chehab 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
3769cb7a01acSMauro Carvalho Chehab 		return -EIO;
3770cb7a01acSMauro Carvalho Chehab 
377110a34367SMauro Carvalho Chehab 	v4l_dbg(1, cx25840_debug, client,
377210a34367SMauro Carvalho Chehab 		"detecting cx25840 client on address 0x%x\n",
377310a34367SMauro Carvalho Chehab 		client->addr << 1);
3774cb7a01acSMauro Carvalho Chehab 
3775cb7a01acSMauro Carvalho Chehab 	device_id = cx25840_read(client, 0x101) << 8;
3776cb7a01acSMauro Carvalho Chehab 	device_id |= cx25840_read(client, 0x100);
3777cb7a01acSMauro Carvalho Chehab 	v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id);
3778cb7a01acSMauro Carvalho Chehab 
377910a34367SMauro Carvalho Chehab 	/*
378010a34367SMauro Carvalho Chehab 	 * The high byte of the device ID should be
378110a34367SMauro Carvalho Chehab 	 * 0x83 for the cx2583x and 0x84 for the cx2584x
378210a34367SMauro Carvalho Chehab 	 */
3783cb7a01acSMauro Carvalho Chehab 	if ((device_id & 0xff00) == 0x8300) {
378429d6a98bSHans Verkuil 		id = CX25836 + ((device_id >> 4) & 0xf) - 6;
3785cb7a01acSMauro Carvalho Chehab 	} else if ((device_id & 0xff00) == 0x8400) {
378629d6a98bSHans Verkuil 		id = CX25840 + ((device_id >> 4) & 0xf);
3787cb7a01acSMauro Carvalho Chehab 	} else if (device_id == 0x0000) {
3788cb7a01acSMauro Carvalho Chehab 		id = get_cx2388x_ident(client);
3789cb7a01acSMauro Carvalho Chehab 	} else if ((device_id & 0xfff0) == 0x5A30) {
3790cb7a01acSMauro Carvalho Chehab 		/* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */
379129d6a98bSHans Verkuil 		id = CX2310X_AV;
3792cb7a01acSMauro Carvalho Chehab 	} else if ((device_id & 0xff) == (device_id >> 8)) {
3793cb7a01acSMauro Carvalho Chehab 		v4l_err(client,
379472cc0671SMauro Carvalho Chehab 			"likely a confused/unresponsive cx2388[578] A/V decoder found @ 0x%x (%s)\n",
3795cb7a01acSMauro Carvalho Chehab 			client->addr << 1, client->adapter->name);
379610a34367SMauro Carvalho Chehab 		v4l_err(client,
379710a34367SMauro Carvalho Chehab 			"A method to reset it from the cx25840 driver software is not known at this time\n");
3798cb7a01acSMauro Carvalho Chehab 		return -ENODEV;
3799cb7a01acSMauro Carvalho Chehab 	} else {
3800cb7a01acSMauro Carvalho Chehab 		v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
3801cb7a01acSMauro Carvalho Chehab 		return -ENODEV;
3802cb7a01acSMauro Carvalho Chehab 	}
3803cb7a01acSMauro Carvalho Chehab 
3804c02b211dSLaurent Pinchart 	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
380510a34367SMauro Carvalho Chehab 	if (!state)
3806cb7a01acSMauro Carvalho Chehab 		return -ENOMEM;
3807cb7a01acSMauro Carvalho Chehab 
3808cb7a01acSMauro Carvalho Chehab 	sd = &state->sd;
3809cb7a01acSMauro Carvalho Chehab 	v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
38108cd61969SMauro Carvalho Chehab #if defined(CONFIG_MEDIA_CONTROLLER)
381118e8d630SMauro Carvalho Chehab 	/*
381218e8d630SMauro Carvalho Chehab 	 * TODO: add media controller support for analog video inputs like
381318e8d630SMauro Carvalho Chehab 	 * composite, svideo, etc.
381418e8d630SMauro Carvalho Chehab 	 * A real input pad for this analog demod would be like:
381518e8d630SMauro Carvalho Chehab 	 *                 ___________
381618e8d630SMauro Carvalho Chehab 	 * TUNER --------> |         |
381718e8d630SMauro Carvalho Chehab 	 *		   |         |
381818e8d630SMauro Carvalho Chehab 	 * SVIDEO .......> | cx25840 |
381918e8d630SMauro Carvalho Chehab 	 *		   |         |
382018e8d630SMauro Carvalho Chehab 	 * COMPOSITE1 ...> |_________|
382118e8d630SMauro Carvalho Chehab 	 *
382218e8d630SMauro Carvalho Chehab 	 * However, at least for now, there's no much gain on modelling
382318e8d630SMauro Carvalho Chehab 	 * those extra inputs. So, let's add it only when needed.
382418e8d630SMauro Carvalho Chehab 	 */
38257e4f23d5SMauro Carvalho Chehab 	state->pads[CX25840_PAD_INPUT].flags = MEDIA_PAD_FL_SINK;
382646c039d0SCody P Schafer 	state->pads[CX25840_PAD_INPUT].sig_type = PAD_SIGNAL_ANALOG;
38277e4f23d5SMauro Carvalho Chehab 	state->pads[CX25840_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE;
382846c039d0SCody P Schafer 	state->pads[CX25840_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV;
38294ca72efaSMauro Carvalho Chehab 	sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
38308cd61969SMauro Carvalho Chehab 
3831ab22e77cSMauro Carvalho Chehab 	ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads),
383218095107SMauro Carvalho Chehab 				     state->pads);
38338cd61969SMauro Carvalho Chehab 	if (ret < 0) {
38348cd61969SMauro Carvalho Chehab 		v4l_info(client, "failed to initialize media entity!\n");
3835db749359SMauro Carvalho Chehab 		return ret;
38368cd61969SMauro Carvalho Chehab 	}
38378cd61969SMauro Carvalho Chehab #endif
3838cb7a01acSMauro Carvalho Chehab 
3839cb7a01acSMauro Carvalho Chehab 	switch (id) {
384029d6a98bSHans Verkuil 	case CX23885_AV:
3841cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n",
3842cb7a01acSMauro Carvalho Chehab 			 client->addr << 1, client->adapter->name);
3843cb7a01acSMauro Carvalho Chehab 		break;
384429d6a98bSHans Verkuil 	case CX23887_AV:
3845cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n",
3846cb7a01acSMauro Carvalho Chehab 			 client->addr << 1, client->adapter->name);
3847cb7a01acSMauro Carvalho Chehab 		break;
384829d6a98bSHans Verkuil 	case CX23888_AV:
3849cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n",
3850cb7a01acSMauro Carvalho Chehab 			 client->addr << 1, client->adapter->name);
3851cb7a01acSMauro Carvalho Chehab 		break;
385229d6a98bSHans Verkuil 	case CX2310X_AV:
3853cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n",
3854cb7a01acSMauro Carvalho Chehab 			 device_id, client->addr << 1, client->adapter->name);
3855cb7a01acSMauro Carvalho Chehab 		break;
385629d6a98bSHans Verkuil 	case CX25840:
385729d6a98bSHans Verkuil 	case CX25841:
385829d6a98bSHans Verkuil 	case CX25842:
385929d6a98bSHans Verkuil 	case CX25843:
386010a34367SMauro Carvalho Chehab 		/*
386110a34367SMauro Carvalho Chehab 		 * Note: revision '(device_id & 0x0f) == 2' was never built.
386210a34367SMauro Carvalho Chehab 		 * The marking skips from 0x1 == 22 to 0x3 == 23.
386310a34367SMauro Carvalho Chehab 		 */
3864cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
3865cb7a01acSMauro Carvalho Chehab 			 (device_id & 0xfff0) >> 4,
3866cb7a01acSMauro Carvalho Chehab 			 (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1
3867cb7a01acSMauro Carvalho Chehab 						: (device_id & 0x0f),
3868cb7a01acSMauro Carvalho Chehab 			 client->addr << 1, client->adapter->name);
3869cb7a01acSMauro Carvalho Chehab 		break;
387029d6a98bSHans Verkuil 	case CX25836:
387129d6a98bSHans Verkuil 	case CX25837:
3872cb7a01acSMauro Carvalho Chehab 	default:
3873cb7a01acSMauro Carvalho Chehab 		v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n",
3874cb7a01acSMauro Carvalho Chehab 			 (device_id & 0xfff0) >> 4, device_id & 0x0f,
3875cb7a01acSMauro Carvalho Chehab 			 client->addr << 1, client->adapter->name);
3876cb7a01acSMauro Carvalho Chehab 		break;
3877cb7a01acSMauro Carvalho Chehab 	}
3878cb7a01acSMauro Carvalho Chehab 
3879cb7a01acSMauro Carvalho Chehab 	state->c = client;
3880cb7a01acSMauro Carvalho Chehab 	state->vid_input = CX25840_COMPOSITE7;
3881cb7a01acSMauro Carvalho Chehab 	state->aud_input = CX25840_AUDIO8;
3882cb7a01acSMauro Carvalho Chehab 	state->audclk_freq = 48000;
3883cb7a01acSMauro Carvalho Chehab 	state->audmode = V4L2_TUNER_MODE_LANG1;
3884cb7a01acSMauro Carvalho Chehab 	state->vbi_line_offset = 8;
3885cb7a01acSMauro Carvalho Chehab 	state->id = id;
3886cb7a01acSMauro Carvalho Chehab 	state->rev = device_id;
3887cdf472d3SHans Verkuil 	state->vbi_regs_offset = id == CX23888_AV ? 0x500 - 0x424 : 0;
3888bfd1bbfbSHans Verkuil 	state->std = V4L2_STD_NTSC_M;
3889cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_init(&state->hdl, 9);
3890cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
3891cb7a01acSMauro Carvalho Chehab 			  V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
3892cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
3893cb7a01acSMauro Carvalho Chehab 			  V4L2_CID_CONTRAST, 0, 127, 1, 64);
3894cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
3895cb7a01acSMauro Carvalho Chehab 			  V4L2_CID_SATURATION, 0, 127, 1, 64);
3896cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
3897cb7a01acSMauro Carvalho Chehab 			  V4L2_CID_HUE, -128, 127, 1, 0);
3898cb7a01acSMauro Carvalho Chehab 	if (!is_cx2583x(state)) {
3899cb7a01acSMauro Carvalho Chehab 		default_volume = cx25840_read(client, 0x8d4);
3900cb7a01acSMauro Carvalho Chehab 		/*
3901cb7a01acSMauro Carvalho Chehab 		 * Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume
3902cb7a01acSMauro Carvalho Chehab 		 * scale mapping limits to avoid -ERANGE errors when
3903cb7a01acSMauro Carvalho Chehab 		 * initializing the volume control
3904cb7a01acSMauro Carvalho Chehab 		 */
3905cb7a01acSMauro Carvalho Chehab 		if (default_volume > 228) {
3906cb7a01acSMauro Carvalho Chehab 			/* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
3907cb7a01acSMauro Carvalho Chehab 			default_volume = 228;
3908cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x8d4, 228);
390910a34367SMauro Carvalho Chehab 		} else if (default_volume < 20) {
3910cb7a01acSMauro Carvalho Chehab 			/* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
3911cb7a01acSMauro Carvalho Chehab 			default_volume = 20;
3912cb7a01acSMauro Carvalho Chehab 			cx25840_write(client, 0x8d4, 20);
3913cb7a01acSMauro Carvalho Chehab 		}
3914cb7a01acSMauro Carvalho Chehab 		default_volume = (((228 - default_volume) >> 1) + 23) << 9;
3915cb7a01acSMauro Carvalho Chehab 
3916cb7a01acSMauro Carvalho Chehab 		state->volume = v4l2_ctrl_new_std(&state->hdl,
391710a34367SMauro Carvalho Chehab 						  &cx25840_audio_ctrl_ops,
391810a34367SMauro Carvalho Chehab 						  V4L2_CID_AUDIO_VOLUME,
391910a34367SMauro Carvalho Chehab 						  0, 65535, 65535 / 100,
392010a34367SMauro Carvalho Chehab 						  default_volume);
3921cb7a01acSMauro Carvalho Chehab 		state->mute = v4l2_ctrl_new_std(&state->hdl,
392210a34367SMauro Carvalho Chehab 						&cx25840_audio_ctrl_ops,
392310a34367SMauro Carvalho Chehab 						V4L2_CID_AUDIO_MUTE,
3924cb7a01acSMauro Carvalho Chehab 						0, 1, 1, 0);
3925cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
3926cb7a01acSMauro Carvalho Chehab 				  V4L2_CID_AUDIO_BALANCE,
3927cb7a01acSMauro Carvalho Chehab 				  0, 65535, 65535 / 100, 32768);
3928cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
3929cb7a01acSMauro Carvalho Chehab 				  V4L2_CID_AUDIO_BASS,
3930cb7a01acSMauro Carvalho Chehab 				  0, 65535, 65535 / 100, 32768);
3931cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
3932cb7a01acSMauro Carvalho Chehab 				  V4L2_CID_AUDIO_TREBLE,
3933cb7a01acSMauro Carvalho Chehab 				  0, 65535, 65535 / 100, 32768);
3934cb7a01acSMauro Carvalho Chehab 	}
3935cb7a01acSMauro Carvalho Chehab 	sd->ctrl_handler = &state->hdl;
3936cb7a01acSMauro Carvalho Chehab 	if (state->hdl.error) {
3937cb7a01acSMauro Carvalho Chehab 		int err = state->hdl.error;
3938cb7a01acSMauro Carvalho Chehab 
3939cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_handler_free(&state->hdl);
3940cb7a01acSMauro Carvalho Chehab 		return err;
3941cb7a01acSMauro Carvalho Chehab 	}
3942cb7a01acSMauro Carvalho Chehab 	if (!is_cx2583x(state))
3943cb7a01acSMauro Carvalho Chehab 		v4l2_ctrl_cluster(2, &state->volume);
3944cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_setup(&state->hdl);
3945cb7a01acSMauro Carvalho Chehab 
3946cb7a01acSMauro Carvalho Chehab 	if (client->dev.platform_data) {
3947cb7a01acSMauro Carvalho Chehab 		struct cx25840_platform_data *pdata = client->dev.platform_data;
3948cb7a01acSMauro Carvalho Chehab 
3949cb7a01acSMauro Carvalho Chehab 		state->pvr150_workaround = pdata->pvr150_workaround;
3950cb7a01acSMauro Carvalho Chehab 	}
3951cb7a01acSMauro Carvalho Chehab 
3952cb7a01acSMauro Carvalho Chehab 	cx25840_ir_probe(sd);
3953cb7a01acSMauro Carvalho Chehab 	return 0;
3954cb7a01acSMauro Carvalho Chehab }
3955cb7a01acSMauro Carvalho Chehab 
cx25840_remove(struct i2c_client * client)3956ed5c2f5fSUwe Kleine-König static void cx25840_remove(struct i2c_client *client)
3957cb7a01acSMauro Carvalho Chehab {
3958cb7a01acSMauro Carvalho Chehab 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
3959cb7a01acSMauro Carvalho Chehab 	struct cx25840_state *state = to_state(sd);
3960cb7a01acSMauro Carvalho Chehab 
3961cb7a01acSMauro Carvalho Chehab 	cx25840_ir_remove(sd);
3962cb7a01acSMauro Carvalho Chehab 	v4l2_device_unregister_subdev(sd);
3963cb7a01acSMauro Carvalho Chehab 	v4l2_ctrl_handler_free(&state->hdl);
3964cb7a01acSMauro Carvalho Chehab }
3965cb7a01acSMauro Carvalho Chehab 
3966cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id cx25840_id[] = {
3967*cc4cbd4bSUwe Kleine-König 	{ "cx25840" },
3968cb7a01acSMauro Carvalho Chehab 	{ }
3969cb7a01acSMauro Carvalho Chehab };
3970cb7a01acSMauro Carvalho Chehab MODULE_DEVICE_TABLE(i2c, cx25840_id);
3971cb7a01acSMauro Carvalho Chehab 
3972cb7a01acSMauro Carvalho Chehab static struct i2c_driver cx25840_driver = {
3973cb7a01acSMauro Carvalho Chehab 	.driver = {
3974cb7a01acSMauro Carvalho Chehab 		.name	= "cx25840",
3975cb7a01acSMauro Carvalho Chehab 	},
3976aaeb31c0SUwe Kleine-König 	.probe		= cx25840_probe,
3977cb7a01acSMauro Carvalho Chehab 	.remove		= cx25840_remove,
3978cb7a01acSMauro Carvalho Chehab 	.id_table	= cx25840_id,
3979cb7a01acSMauro Carvalho Chehab };
3980cb7a01acSMauro Carvalho Chehab 
3981cb7a01acSMauro Carvalho Chehab module_i2c_driver(cx25840_driver);
3982