aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/adv7170.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/adv7170.c')
-rw-r--r--drivers/media/video/adv7170.c321
1 files changed, 168 insertions, 153 deletions
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index ebafe78cb4c0..f7120b369ba2 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -34,15 +34,23 @@
34#include <asm/uaccess.h> 34#include <asm/uaccess.h>
35#include <linux/i2c.h> 35#include <linux/i2c.h>
36#include <linux/i2c-id.h> 36#include <linux/i2c-id.h>
37#include <linux/videodev.h> 37#include <linux/videodev2.h>
38#include <linux/video_encoder.h> 38#include <media/v4l2-device.h>
39#include <media/v4l2-common.h> 39#include <media/v4l2-chip-ident.h>
40#include <media/v4l2-i2c-drv-legacy.h> 40#include <media/v4l2-i2c-drv-legacy.h>
41 41
42MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver"); 42MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
43MODULE_AUTHOR("Maxim Yevtyushkin"); 43MODULE_AUTHOR("Maxim Yevtyushkin");
44MODULE_LICENSE("GPL"); 44MODULE_LICENSE("GPL");
45 45
46static unsigned short normal_i2c[] = {
47 0xd4 >> 1, 0xd6 >> 1, /* adv7170 IDs */
48 0x54 >> 1, 0x56 >> 1, /* adv7171 IDs */
49 I2C_CLIENT_END
50};
51
52I2C_CLIENT_INSMOD;
53
46static int debug; 54static int debug;
47module_param(debug, int, 0); 55module_param(debug, int, 0);
48MODULE_PARM_DESC(debug, "Debug level (0-1)"); 56MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -50,36 +58,43 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
50/* ----------------------------------------------------------------------- */ 58/* ----------------------------------------------------------------------- */
51 59
52struct adv7170 { 60struct adv7170 {
61 struct v4l2_subdev sd;
53 unsigned char reg[128]; 62 unsigned char reg[128];
54 63
55 v4l2_std_id norm; 64 v4l2_std_id norm;
56 int input; 65 int input;
57 int bright;
58 int contrast;
59 int hue;
60 int sat;
61}; 66};
62 67
68static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
69{
70 return container_of(sd, struct adv7170, sd);
71}
72
63static char *inputs[] = { "pass_through", "play_back" }; 73static char *inputs[] = { "pass_through", "play_back" };
64 74
65/* ----------------------------------------------------------------------- */ 75/* ----------------------------------------------------------------------- */
66 76
67static inline int adv7170_write(struct i2c_client *client, u8 reg, u8 value) 77static inline int adv7170_write(struct v4l2_subdev *sd, u8 reg, u8 value)
68{ 78{
69 struct adv7170 *encoder = i2c_get_clientdata(client); 79 struct i2c_client *client = v4l2_get_subdevdata(sd);
80 struct adv7170 *encoder = to_adv7170(sd);
70 81
71 encoder->reg[reg] = value; 82 encoder->reg[reg] = value;
72 return i2c_smbus_write_byte_data(client, reg, value); 83 return i2c_smbus_write_byte_data(client, reg, value);
73} 84}
74 85
75static inline int adv7170_read(struct i2c_client *client, u8 reg) 86static inline int adv7170_read(struct v4l2_subdev *sd, u8 reg)
76{ 87{
88 struct i2c_client *client = v4l2_get_subdevdata(sd);
89
77 return i2c_smbus_read_byte_data(client, reg); 90 return i2c_smbus_read_byte_data(client, reg);
78} 91}
79 92
80static int adv7170_write_block(struct i2c_client *client, 93static int adv7170_write_block(struct v4l2_subdev *sd,
81 const u8 *data, unsigned int len) 94 const u8 *data, unsigned int len)
82{ 95{
96 struct i2c_client *client = v4l2_get_subdevdata(sd);
97 struct adv7170 *encoder = to_adv7170(sd);
83 int ret = -1; 98 int ret = -1;
84 u8 reg; 99 u8 reg;
85 100
@@ -87,7 +102,6 @@ static int adv7170_write_block(struct i2c_client *client,
87 * the adapter understands raw I2C */ 102 * the adapter understands raw I2C */
88 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 103 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
89 /* do raw I2C, not smbus compatible */ 104 /* do raw I2C, not smbus compatible */
90 struct adv7170 *encoder = i2c_get_clientdata(client);
91 u8 block_data[32]; 105 u8 block_data[32];
92 int block_len; 106 int block_len;
93 107
@@ -108,7 +122,7 @@ static int adv7170_write_block(struct i2c_client *client,
108 /* do some slow I2C emulation kind of thing */ 122 /* do some slow I2C emulation kind of thing */
109 while (len >= 2) { 123 while (len >= 2) {
110 reg = *data++; 124 reg = *data++;
111 ret = adv7170_write(client, reg, *data++); 125 ret = adv7170_write(sd, reg, *data++);
112 if (ret < 0) 126 if (ret < 0)
113 break; 127 break;
114 len -= 2; 128 len -= 2;
@@ -126,168 +140,165 @@ static int adv7170_write_block(struct i2c_client *client,
126#define TR1PLAY 0x00 140#define TR1PLAY 0x00
127 141
128static const unsigned char init_NTSC[] = { 142static const unsigned char init_NTSC[] = {
129 0x00, 0x10, // MR0 143 0x00, 0x10, /* MR0 */
130 0x01, 0x20, // MR1 144 0x01, 0x20, /* MR1 */
131 0x02, 0x0e, // MR2 RTC control: bits 2 and 1 145 0x02, 0x0e, /* MR2 RTC control: bits 2 and 1 */
132 0x03, 0x80, // MR3 146 0x03, 0x80, /* MR3 */
133 0x04, 0x30, // MR4 147 0x04, 0x30, /* MR4 */
134 0x05, 0x00, // Reserved 148 0x05, 0x00, /* Reserved */
135 0x06, 0x00, // Reserved 149 0x06, 0x00, /* Reserved */
136 0x07, TR0MODE, // TM0 150 0x07, TR0MODE, /* TM0 */
137 0x08, TR1CAPT, // TM1 151 0x08, TR1CAPT, /* TM1 */
138 0x09, 0x16, // Fsc0 152 0x09, 0x16, /* Fsc0 */
139 0x0a, 0x7c, // Fsc1 153 0x0a, 0x7c, /* Fsc1 */
140 0x0b, 0xf0, // Fsc2 154 0x0b, 0xf0, /* Fsc2 */
141 0x0c, 0x21, // Fsc3 155 0x0c, 0x21, /* Fsc3 */
142 0x0d, 0x00, // Subcarrier Phase 156 0x0d, 0x00, /* Subcarrier Phase */
143 0x0e, 0x00, // Closed Capt. Ext 0 157 0x0e, 0x00, /* Closed Capt. Ext 0 */
144 0x0f, 0x00, // Closed Capt. Ext 1 158 0x0f, 0x00, /* Closed Capt. Ext 1 */
145 0x10, 0x00, // Closed Capt. 0 159 0x10, 0x00, /* Closed Capt. 0 */
146 0x11, 0x00, // Closed Capt. 1 160 0x11, 0x00, /* Closed Capt. 1 */
147 0x12, 0x00, // Pedestal Ctl 0 161 0x12, 0x00, /* Pedestal Ctl 0 */
148 0x13, 0x00, // Pedestal Ctl 1 162 0x13, 0x00, /* Pedestal Ctl 1 */
149 0x14, 0x00, // Pedestal Ctl 2 163 0x14, 0x00, /* Pedestal Ctl 2 */
150 0x15, 0x00, // Pedestal Ctl 3 164 0x15, 0x00, /* Pedestal Ctl 3 */
151 0x16, 0x00, // CGMS_WSS_0 165 0x16, 0x00, /* CGMS_WSS_0 */
152 0x17, 0x00, // CGMS_WSS_1 166 0x17, 0x00, /* CGMS_WSS_1 */
153 0x18, 0x00, // CGMS_WSS_2 167 0x18, 0x00, /* CGMS_WSS_2 */
154 0x19, 0x00, // Teletext Ctl 168 0x19, 0x00, /* Teletext Ctl */
155}; 169};
156 170
157static const unsigned char init_PAL[] = { 171static const unsigned char init_PAL[] = {
158 0x00, 0x71, // MR0 172 0x00, 0x71, /* MR0 */
159 0x01, 0x20, // MR1 173 0x01, 0x20, /* MR1 */
160 0x02, 0x0e, // MR2 RTC control: bits 2 and 1 174 0x02, 0x0e, /* MR2 RTC control: bits 2 and 1 */
161 0x03, 0x80, // MR3 175 0x03, 0x80, /* MR3 */
162 0x04, 0x30, // MR4 176 0x04, 0x30, /* MR4 */
163 0x05, 0x00, // Reserved 177 0x05, 0x00, /* Reserved */
164 0x06, 0x00, // Reserved 178 0x06, 0x00, /* Reserved */
165 0x07, TR0MODE, // TM0 179 0x07, TR0MODE, /* TM0 */
166 0x08, TR1CAPT, // TM1 180 0x08, TR1CAPT, /* TM1 */
167 0x09, 0xcb, // Fsc0 181 0x09, 0xcb, /* Fsc0 */
168 0x0a, 0x8a, // Fsc1 182 0x0a, 0x8a, /* Fsc1 */
169 0x0b, 0x09, // Fsc2 183 0x0b, 0x09, /* Fsc2 */
170 0x0c, 0x2a, // Fsc3 184 0x0c, 0x2a, /* Fsc3 */
171 0x0d, 0x00, // Subcarrier Phase 185 0x0d, 0x00, /* Subcarrier Phase */
172 0x0e, 0x00, // Closed Capt. Ext 0 186 0x0e, 0x00, /* Closed Capt. Ext 0 */
173 0x0f, 0x00, // Closed Capt. Ext 1 187 0x0f, 0x00, /* Closed Capt. Ext 1 */
174 0x10, 0x00, // Closed Capt. 0 188 0x10, 0x00, /* Closed Capt. 0 */
175 0x11, 0x00, // Closed Capt. 1 189 0x11, 0x00, /* Closed Capt. 1 */
176 0x12, 0x00, // Pedestal Ctl 0 190 0x12, 0x00, /* Pedestal Ctl 0 */
177 0x13, 0x00, // Pedestal Ctl 1 191 0x13, 0x00, /* Pedestal Ctl 1 */
178 0x14, 0x00, // Pedestal Ctl 2 192 0x14, 0x00, /* Pedestal Ctl 2 */
179 0x15, 0x00, // Pedestal Ctl 3 193 0x15, 0x00, /* Pedestal Ctl 3 */
180 0x16, 0x00, // CGMS_WSS_0 194 0x16, 0x00, /* CGMS_WSS_0 */
181 0x17, 0x00, // CGMS_WSS_1 195 0x17, 0x00, /* CGMS_WSS_1 */
182 0x18, 0x00, // CGMS_WSS_2 196 0x18, 0x00, /* CGMS_WSS_2 */
183 0x19, 0x00, // Teletext Ctl 197 0x19, 0x00, /* Teletext Ctl */
184}; 198};
185 199
186 200
187static int adv7170_command(struct i2c_client *client, unsigned cmd, void *arg) 201static int adv7170_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
188{ 202{
189 struct adv7170 *encoder = i2c_get_clientdata(client); 203 struct adv7170 *encoder = to_adv7170(sd);
190 204
191 switch (cmd) { 205 v4l2_dbg(1, debug, sd, "set norm %llx\n", std);
192 case VIDIOC_INT_INIT: 206
193#if 0 207 if (std & V4L2_STD_NTSC) {
194 /* This is just for testing!!! */ 208 adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
195 adv7170_write_block(client, init_common, 209 if (encoder->input == 0)
196 sizeof(init_common)); 210 adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
197 adv7170_write(client, 0x07, TR0MODE | TR0RST); 211 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
198 adv7170_write(client, 0x07, TR0MODE); 212 adv7170_write(sd, 0x07, TR0MODE);
199#endif 213 } else if (std & V4L2_STD_PAL) {
200 break; 214 adv7170_write_block(sd, init_PAL, sizeof(init_PAL));
201 215 if (encoder->input == 0)
202 case VIDIOC_INT_S_STD_OUTPUT: 216 adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
203 { 217 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
204 v4l2_std_id iarg = *(v4l2_std_id *) arg; 218 adv7170_write(sd, 0x07, TR0MODE);
205 219 } else {
206 v4l_dbg(1, debug, client, "set norm %llx\n", iarg); 220 v4l2_dbg(1, debug, sd, "illegal norm: %llx\n", std);
207 221 return -EINVAL;
208 if (iarg & V4L2_STD_NTSC) {
209 adv7170_write_block(client, init_NTSC,
210 sizeof(init_NTSC));
211 if (encoder->input == 0)
212 adv7170_write(client, 0x02, 0x0e); // Enable genlock
213 adv7170_write(client, 0x07, TR0MODE | TR0RST);
214 adv7170_write(client, 0x07, TR0MODE);
215 } else if (iarg & V4L2_STD_PAL) {
216 adv7170_write_block(client, init_PAL,
217 sizeof(init_PAL));
218 if (encoder->input == 0)
219 adv7170_write(client, 0x02, 0x0e); // Enable genlock
220 adv7170_write(client, 0x07, TR0MODE | TR0RST);
221 adv7170_write(client, 0x07, TR0MODE);
222 } else {
223 v4l_dbg(1, debug, client, "illegal norm: %llx\n", iarg);
224 return -EINVAL;
225 }
226 v4l_dbg(1, debug, client, "switched to %llx\n", iarg);
227 encoder->norm = iarg;
228 break;
229 } 222 }
223 v4l2_dbg(1, debug, sd, "switched to %llx\n", std);
224 encoder->norm = std;
225 return 0;
226}
230 227
231 case VIDIOC_INT_S_VIDEO_ROUTING: 228static int adv7170_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *route)
232 { 229{
233 struct v4l2_routing *route = arg; 230 struct adv7170 *encoder = to_adv7170(sd);
234 231
235 /* RJ: *iarg = 0: input is from decoder 232 /* RJ: route->input = 0: input is from decoder
236 *iarg = 1: input is from ZR36060 233 route->input = 1: input is from ZR36060
237 *iarg = 2: color bar */ 234 route->input = 2: color bar */
238 235
239 v4l_dbg(1, debug, client, "set input from %s\n", 236 v4l2_dbg(1, debug, sd, "set input from %s\n",
240 route->input == 0 ? "decoder" : "ZR36060"); 237 route->input == 0 ? "decoder" : "ZR36060");
241 238
242 switch (route->input) { 239 switch (route->input) {
243 case 0: 240 case 0:
244 adv7170_write(client, 0x01, 0x20); 241 adv7170_write(sd, 0x01, 0x20);
245 adv7170_write(client, 0x08, TR1CAPT); /* TR1 */ 242 adv7170_write(sd, 0x08, TR1CAPT); /* TR1 */
246 adv7170_write(client, 0x02, 0x0e); // Enable genlock 243 adv7170_write(sd, 0x02, 0x0e); /* Enable genlock */
247 adv7170_write(client, 0x07, TR0MODE | TR0RST); 244 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
248 adv7170_write(client, 0x07, TR0MODE); 245 adv7170_write(sd, 0x07, TR0MODE);
249 /* udelay(10); */ 246 /* udelay(10); */
250 break; 247 break;
251 248
252 case 1: 249 case 1:
253 adv7170_write(client, 0x01, 0x00); 250 adv7170_write(sd, 0x01, 0x00);
254 adv7170_write(client, 0x08, TR1PLAY); /* TR1 */ 251 adv7170_write(sd, 0x08, TR1PLAY); /* TR1 */
255 adv7170_write(client, 0x02, 0x08); 252 adv7170_write(sd, 0x02, 0x08);
256 adv7170_write(client, 0x07, TR0MODE | TR0RST); 253 adv7170_write(sd, 0x07, TR0MODE | TR0RST);
257 adv7170_write(client, 0x07, TR0MODE); 254 adv7170_write(sd, 0x07, TR0MODE);
258 /* udelay(10); */ 255 /* udelay(10); */
259 break;
260
261 default:
262 v4l_dbg(1, debug, client, "illegal input: %d\n", route->input);
263 return -EINVAL;
264 }
265 v4l_dbg(1, debug, client, "switched to %s\n", inputs[route->input]);
266 encoder->input = route->input;
267 break; 256 break;
268 }
269 257
270 default: 258 default:
259 v4l2_dbg(1, debug, sd, "illegal input: %d\n", route->input);
271 return -EINVAL; 260 return -EINVAL;
272 } 261 }
273 262 v4l2_dbg(1, debug, sd, "switched to %s\n", inputs[route->input]);
263 encoder->input = route->input;
274 return 0; 264 return 0;
275} 265}
276 266
267static int adv7170_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
268{
269 struct i2c_client *client = v4l2_get_subdevdata(sd);
270
271 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0);
272}
273
274static int adv7170_command(struct i2c_client *client, unsigned cmd, void *arg)
275{
276 return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg);
277}
278
277/* ----------------------------------------------------------------------- */ 279/* ----------------------------------------------------------------------- */
278 280
279static unsigned short normal_i2c[] = { 281static const struct v4l2_subdev_core_ops adv7170_core_ops = {
280 0xd4 >> 1, 0xd6 >> 1, /* adv7170 IDs */ 282 .g_chip_ident = adv7170_g_chip_ident,
281 0x54 >> 1, 0x56 >> 1, /* adv7171 IDs */
282 I2C_CLIENT_END
283}; 283};
284 284
285I2C_CLIENT_INSMOD; 285static const struct v4l2_subdev_video_ops adv7170_video_ops = {
286 .s_std_output = adv7170_s_std_output,
287 .s_routing = adv7170_s_routing,
288};
289
290static const struct v4l2_subdev_ops adv7170_ops = {
291 .core = &adv7170_core_ops,
292 .video = &adv7170_video_ops,
293};
294
295/* ----------------------------------------------------------------------- */
286 296
287static int adv7170_probe(struct i2c_client *client, 297static int adv7170_probe(struct i2c_client *client,
288 const struct i2c_device_id *id) 298 const struct i2c_device_id *id)
289{ 299{
290 struct adv7170 *encoder; 300 struct adv7170 *encoder;
301 struct v4l2_subdev *sd;
291 int i; 302 int i;
292 303
293 /* Check if the adapter supports the needed features */ 304 /* Check if the adapter supports the needed features */
@@ -300,25 +311,29 @@ static int adv7170_probe(struct i2c_client *client,
300 encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL); 311 encoder = kzalloc(sizeof(struct adv7170), GFP_KERNEL);
301 if (encoder == NULL) 312 if (encoder == NULL)
302 return -ENOMEM; 313 return -ENOMEM;
314 sd = &encoder->sd;
315 v4l2_i2c_subdev_init(sd, client, &adv7170_ops);
303 encoder->norm = V4L2_STD_NTSC; 316 encoder->norm = V4L2_STD_NTSC;
304 encoder->input = 0; 317 encoder->input = 0;
305 i2c_set_clientdata(client, encoder);
306 318
307 i = adv7170_write_block(client, init_NTSC, sizeof(init_NTSC)); 319 i = adv7170_write_block(sd, init_NTSC, sizeof(init_NTSC));
308 if (i >= 0) { 320 if (i >= 0) {
309 i = adv7170_write(client, 0x07, TR0MODE | TR0RST); 321 i = adv7170_write(sd, 0x07, TR0MODE | TR0RST);
310 i = adv7170_write(client, 0x07, TR0MODE); 322 i = adv7170_write(sd, 0x07, TR0MODE);
311 i = adv7170_read(client, 0x12); 323 i = adv7170_read(sd, 0x12);
312 v4l_dbg(1, debug, client, "revision %d\n", i & 1); 324 v4l2_dbg(1, debug, sd, "revision %d\n", i & 1);
313 } 325 }
314 if (i < 0) 326 if (i < 0)
315 v4l_dbg(1, debug, client, "init error 0x%x\n", i); 327 v4l2_dbg(1, debug, sd, "init error 0x%x\n", i);
316 return 0; 328 return 0;
317} 329}
318 330
319static int adv7170_remove(struct i2c_client *client) 331static int adv7170_remove(struct i2c_client *client)
320{ 332{
321 kfree(i2c_get_clientdata(client)); 333 struct v4l2_subdev *sd = i2c_get_clientdata(client);
334
335 v4l2_device_unregister_subdev(sd);
336 kfree(to_adv7170(sd));
322 return 0; 337 return 0;
323} 338}
324 339