1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include "matroxfb_maven.h"
16#include "matroxfb_misc.h"
17#include "matroxfb_DAC1064.h"
18#include <linux/i2c.h>
19#include <linux/matroxfb.h>
20#include <linux/slab.h>
21#include <asm/div64.h>
22
23#define MGATVO_B 1
24#define MGATVO_C 2
25
26static const struct maven_gamma {
27 unsigned char reg83;
28 unsigned char reg84;
29 unsigned char reg85;
30 unsigned char reg86;
31 unsigned char reg87;
32 unsigned char reg88;
33 unsigned char reg89;
34 unsigned char reg8a;
35 unsigned char reg8b;
36} maven_gamma[] = {
37 { 131, 57, 223, 15, 117, 212, 251, 91, 156},
38 { 133, 61, 128, 63, 180, 147, 195, 100, 180},
39 { 131, 19, 63, 31, 50, 66, 171, 64, 176},
40 { 0, 0, 0, 31, 16, 16, 16, 100, 200},
41 { 8, 23, 47, 73, 147, 244, 220, 80, 195},
42 { 22, 43, 64, 80, 147, 115, 58, 85, 168},
43 { 34, 60, 80, 214, 147, 212, 188, 85, 167},
44 { 45, 77, 96, 216, 147, 99, 91, 85, 159},
45 { 56, 76, 112, 107, 147, 212, 148, 64, 144},
46 { 65, 91, 128, 137, 147, 196, 17, 69, 148},
47 { 72, 104, 136, 138, 147, 180, 245, 73, 147},
48 { 87, 116, 143, 126, 16, 83, 229, 77, 144},
49 { 95, 119, 152, 254, 244, 83, 221, 77, 151},
50 { 100, 129, 159, 156, 244, 148, 197, 77, 160},
51 { 105, 141, 167, 247, 244, 132, 181, 84, 166},
52 { 105, 147, 168, 247, 244, 245, 181, 90, 170},
53 { 120, 153, 175, 248, 212, 229, 165, 90, 180},
54 { 119, 156, 176, 248, 244, 229, 84, 74, 160},
55 { 119, 158, 183, 248, 244, 229, 149, 78, 165}
56};
57
58
59struct mctl {
60 struct v4l2_queryctrl desc;
61 size_t control;
62};
63
64#define BLMIN 0x0FF
65#define WLMAX 0x3FF
66
67static const struct mctl maven_controls[] =
68{ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
69 "brightness",
70 0, WLMAX - BLMIN, 1, 379 - BLMIN,
71 0,
72 }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
73 { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
74 "contrast",
75 0, 1023, 1, 127,
76 0,
77 }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
78 { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
79 "saturation",
80 0, 255, 1, 155,
81 0,
82 }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
83 { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
84 "hue",
85 0, 255, 1, 0,
86 0,
87 }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
88 { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER,
89 "gamma",
90 0, ARRAY_SIZE(maven_gamma) - 1, 1, 3,
91 0,
92 }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
93 { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
94 "test output",
95 0, 1, 1, 0,
96 0,
97 }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
98 { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER,
99 "deflicker mode",
100 0, 2, 1, 0,
101 0,
102 }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
103
104};
105
106#define MAVCTRLS ARRAY_SIZE(maven_controls)
107
108
109
110
111static int get_ctrl_id(__u32 v4l2_id) {
112 int i;
113
114 for (i = 0; i < MAVCTRLS; i++) {
115 if (v4l2_id < maven_controls[i].desc.id) {
116 if (maven_controls[i].desc.id == 0x08000000) {
117 return -EINVAL;
118 }
119 return -ENOENT;
120 }
121 if (v4l2_id == maven_controls[i].desc.id) {
122 return i;
123 }
124 }
125 return -EINVAL;
126}
127
128struct maven_data {
129 struct matrox_fb_info* primary_head;
130 struct i2c_client *client;
131 int version;
132};
133
134static int* get_ctrl_ptr(struct maven_data* md, int idx) {
135 return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
136}
137
138static int maven_get_reg(struct i2c_client* c, char reg) {
139 char dst;
140 struct i2c_msg msgs[] = {
141 {
142 .addr = c->addr,
143 .flags = I2C_M_REV_DIR_ADDR,
144 .len = sizeof(reg),
145 .buf = ®
146 },
147 {
148 .addr = c->addr,
149 .flags = I2C_M_RD | I2C_M_NOSTART,
150 .len = sizeof(dst),
151 .buf = &dst
152 }
153 };
154 s32 err;
155
156 err = i2c_transfer(c->adapter, msgs, 2);
157 if (err < 0)
158 printk(KERN_INFO "ReadReg(%d) failed\n", reg);
159 return dst & 0xFF;
160}
161
162static int maven_set_reg(struct i2c_client* c, int reg, int val) {
163 s32 err;
164
165 err = i2c_smbus_write_byte_data(c, reg, val);
166 if (err)
167 printk(KERN_INFO "WriteReg(%d) failed\n", reg);
168 return err;
169}
170
171static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
172 s32 err;
173
174 err = i2c_smbus_write_word_data(c, reg, val);
175 if (err)
176 printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
177 return err;
178}
179
180static const struct matrox_pll_features maven_pll = {
181 50000,
182 27000,
183 4, 127,
184 2, 31,
185 3
186};
187
188struct matrox_pll_features2 {
189 unsigned int vco_freq_min;
190 unsigned int vco_freq_max;
191 unsigned int feed_div_min;
192 unsigned int feed_div_max;
193 unsigned int in_div_min;
194 unsigned int in_div_max;
195 unsigned int post_shift_max;
196};
197
198struct matrox_pll_ctl {
199 unsigned int ref_freq;
200 unsigned int den;
201};
202
203static const struct matrox_pll_features2 maven1000_pll = {
204 .vco_freq_min = 50000000,
205 .vco_freq_max = 300000000,
206 .feed_div_min = 5,
207 .feed_div_max = 128,
208 .in_div_min = 3,
209 .in_div_max = 32,
210 .post_shift_max = 3
211};
212
213static const struct matrox_pll_ctl maven_PAL = {
214 .ref_freq = 540000,
215 .den = 50
216};
217
218static const struct matrox_pll_ctl maven_NTSC = {
219 .ref_freq = 450450,
220 .den = 60
221};
222
223static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
224 const struct matrox_pll_ctl* ctl,
225 unsigned int htotal, unsigned int vtotal,
226 unsigned int* in, unsigned int* feed, unsigned int* post,
227 unsigned int* h2) {
228 unsigned int besth2 = 0;
229 unsigned int fxtal = ctl->ref_freq;
230 unsigned int fmin = pll->vco_freq_min / ctl->den;
231 unsigned int fwant;
232 unsigned int p;
233 unsigned int scrlen;
234 unsigned int fmax;
235
236 DBG(__func__)
237
238 scrlen = htotal * (vtotal - 1);
239 fwant = htotal * vtotal;
240 fmax = pll->vco_freq_max / ctl->den;
241
242 dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
243 fwant, fxtal, htotal, vtotal, fmax);
244 for (p = 1; p <= pll->post_shift_max; p++) {
245 if (fwant * 2 > fmax)
246 break;
247 fwant *= 2;
248 }
249 if (fwant > fmax)
250 return 0;
251 for (; p-- > 0; fwant >>= 1) {
252 unsigned int m;
253
254 if (fwant < fmin) break;
255 for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
256 unsigned int n;
257 unsigned int dvd;
258 unsigned int ln;
259
260 n = (fwant * m) / fxtal;
261 if (n < pll->feed_div_min)
262 continue;
263 if (n > pll->feed_div_max)
264 break;
265
266 ln = fxtal * n;
267 dvd = m << p;
268
269 if (ln % dvd)
270 continue;
271 ln = ln / dvd;
272
273 if (ln < scrlen + 2)
274 continue;
275 ln = ln - scrlen;
276 if (ln > htotal)
277 continue;
278 dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
279 if (ln > besth2) {
280 dprintk(KERN_DEBUG "Better...\n");
281 *h2 = besth2 = ln;
282 *post = p;
283 *in = m;
284 *feed = n;
285 }
286 }
287 }
288
289
290 if (besth2 < 2)
291 return 0;
292
293 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
294 return fxtal * (*feed) / (*in) * ctl->den;
295}
296
297static int matroxfb_mavenclock(const struct matrox_pll_ctl *ctl,
298 unsigned int htotal, unsigned int vtotal,
299 unsigned int* in, unsigned int* feed, unsigned int* post,
300 unsigned int* htotal2) {
301 unsigned int fvco;
302 unsigned int uninitialized_var(p);
303
304 fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
305 if (!fvco)
306 return -EINVAL;
307 p = (1 << p) - 1;
308 if (fvco <= 100000000)
309 ;
310 else if (fvco <= 140000000)
311 p |= 0x08;
312 else if (fvco <= 180000000)
313 p |= 0x10;
314 else
315 p |= 0x18;
316 *post = p;
317 return 0;
318}
319
320static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
321 unsigned int* in, unsigned int* feed, unsigned int* post) {
322 unsigned int fvco;
323 unsigned int p;
324
325 fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
326 p = (1 << p) - 1;
327 if (fvco <= 100000)
328 ;
329 else if (fvco <= 140000)
330 p |= 0x08;
331 else if (fvco <= 180000)
332 p |= 0x10;
333 else
334 p |= 0x18;
335 *post = p;
336 return;
337}
338
339static unsigned char maven_compute_deflicker (const struct maven_data* md) {
340 unsigned char df;
341
342 df = (md->version == MGATVO_B?0x40:0x00);
343 switch (md->primary_head->altout.tvo_params.deflicker) {
344 case 0:
345
346 break;
347 case 1:
348 df |= 0xB1;
349 break;
350 case 2:
351 df |= 0xA2;
352 break;
353 }
354 return df;
355}
356
357static void maven_compute_bwlevel (const struct maven_data* md,
358 int *bl, int *wl) {
359 const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
360 const int c = md->primary_head->altout.tvo_params.contrast;
361
362 *bl = max(b - c, BLMIN);
363 *wl = min(b + c, WLMAX);
364}
365
366static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
367 return maven_gamma + md->primary_head->altout.tvo_params.gamma;
368}
369
370
371static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
372 static struct mavenregs palregs = { {
373 0x2A, 0x09, 0x8A, 0xCB,
374 0x00,
375 0x00,
376 0x00,
377 0x00,
378 0x7E,
379 0x44,
380 0x9C,
381 0x2E,
382 0x21,
383 0x00,
384 0x3F, 0x03,
385 0x3F, 0x03,
386 0x1A,
387 0x2A,
388 0x1C, 0x3D, 0x14,
389 0x9C, 0x01,
390 0x00,
391 0xFE,
392 0x7E,
393 0x60,
394 0x05,
395 0x89, 0x03,
396 0x72,
397 0x07,
398 0x72,
399 0x00,
400 0x00,
401 0x00,
402 0x08,
403 0x04,
404 0x00,
405 0x1A,
406 0x55, 0x01,
407 0x26,
408 0x07, 0x7E,
409 0x02, 0x54,
410 0xB0, 0x00,
411 0x14,
412 0x49,
413 0x00,
414 0x00,
415 0xA3,
416 0xC8,
417 0x22,
418 0x02,
419 0x22,
420 0x3F, 0x03,
421 0x00,
422 0x00,
423 }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
424 static struct mavenregs ntscregs = { {
425 0x21, 0xF0, 0x7C, 0x1F,
426 0x00,
427 0x00,
428 0x00,
429 0x00,
430 0x7E,
431 0x43,
432 0x7E,
433 0x3D,
434 0x00,
435 0x00,
436 0x41, 0x00,
437 0x3C, 0x00,
438 0x17,
439 0x21,
440 0x1B, 0x1B, 0x24,
441 0x83, 0x01,
442 0x00,
443 0x0F,
444 0x0F,
445 0x60,
446 0x05,
447 0x89, 0x02,
448 0x5F,
449 0x04,
450 0x5F,
451 0x01,
452 0x02,
453 0x00,
454 0x0A,
455 0x05,
456 0x00,
457 0x10,
458 0xFF, 0x03,
459 0x24,
460 0x0F, 0x78,
461 0x00, 0x00,
462 0xB2, 0x04,
463 0x14,
464 0x02,
465 0x00,
466 0x00,
467 0xA3,
468 0xC8,
469 0x15,
470 0x05,
471 0x3B,
472 0x3C, 0x00,
473 0x00,
474 0x00,
475 }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
476 struct matrox_fb_info *minfo = md->primary_head;
477
478 if (minfo->outputs[1].mode == MATROXFB_OUTPUT_MODE_PAL)
479 *data = palregs;
480 else
481 *data = ntscregs;
482
483
484 data->regs[0x93] = maven_compute_deflicker(md);
485
486
487 {
488 const struct maven_gamma* g;
489 g = maven_compute_gamma(md);
490 data->regs[0x83] = g->reg83;
491 data->regs[0x84] = g->reg84;
492 data->regs[0x85] = g->reg85;
493 data->regs[0x86] = g->reg86;
494 data->regs[0x87] = g->reg87;
495 data->regs[0x88] = g->reg88;
496 data->regs[0x89] = g->reg89;
497 data->regs[0x8A] = g->reg8a;
498 data->regs[0x8B] = g->reg8b;
499 }
500
501
502 {
503 int bl, wl;
504 maven_compute_bwlevel (md, &bl, &wl);
505 data->regs[0x0e] = bl >> 2;
506 data->regs[0x0f] = bl & 3;
507 data->regs[0x1e] = wl >> 2;
508 data->regs[0x1f] = wl & 3;
509 }
510
511
512 {
513 data->regs[0x20] =
514 data->regs[0x22] = minfo->altout.tvo_params.saturation;
515 }
516
517
518 data->regs[0x25] = minfo->altout.tvo_params.hue;
519 return;
520}
521
522#define LR(x) maven_set_reg(c, (x), m->regs[(x)])
523#define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
524static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
525 int val;
526
527
528 maven_set_reg(c, 0x3E, 0x01);
529 maven_get_reg(c, 0x82);
530 maven_set_reg(c, 0x8C, 0x00);
531 maven_get_reg(c, 0x94);
532 maven_set_reg(c, 0x94, 0xA2);
533
534
535 maven_set_reg_pair(c, 0x8E, 0x1EFF);
536 maven_set_reg(c, 0xC6, 0x01);
537
538
539
540 maven_get_reg(c, 0x06);
541 maven_set_reg(c, 0x06, 0xF9);
542
543
544
545
546
547 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
548
549 LR(0x04);
550
551 LR(0x2C);
552 LR(0x08);
553 LR(0x0A);
554 LR(0x09);
555 LR(0x29);
556 LRP(0x31);
557 LRP(0x17);
558 LR(0x0B);
559 LR(0x0C);
560 if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
561 maven_set_reg(c, 0x35, 0x10);
562 } else {
563 maven_set_reg(c, 0x35, 0x0F);
564 }
565
566 LRP(0x10);
567
568 LRP(0x0E);
569 LRP(0x1E);
570
571 LR(0x20);
572 LR(0x22);
573 LR(0x25);
574 LR(0x34);
575 LR(0x33);
576 LR(0x19);
577 LR(0x12);
578 LR(0x3B);
579 LR(0x13);
580 LR(0x39);
581 LR(0x1D);
582 LR(0x3A);
583 LR(0x24);
584 LR(0x14);
585 LR(0x15);
586 LR(0x16);
587 LRP(0x2D);
588 LRP(0x2F);
589 LR(0x1A);
590 LR(0x1B);
591 LR(0x1C);
592 LR(0x23);
593 LR(0x26);
594 LR(0x28);
595 LR(0x27);
596 LR(0x21);
597 LRP(0x2A);
598 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
599 maven_set_reg(c, 0x35, 0x1D);
600 else
601 maven_set_reg(c, 0x35, 0x1C);
602
603 LRP(0x3C);
604 LR(0x37);
605 LR(0x38);
606 maven_set_reg(c, 0xB3, 0x01);
607
608 maven_get_reg(c, 0xB0);
609 maven_set_reg(c, 0xB0, 0x08);
610 maven_get_reg(c, 0xB9);
611 maven_set_reg(c, 0xB9, 0x78);
612 maven_get_reg(c, 0xBF);
613 maven_set_reg(c, 0xBF, 0x02);
614 maven_get_reg(c, 0x94);
615 maven_set_reg(c, 0x94, 0xB3);
616
617 LR(0x80);
618 LR(0x81);
619 LR(0x82);
620
621 maven_set_reg(c, 0x8C, 0x20);
622 maven_get_reg(c, 0x8D);
623 maven_set_reg(c, 0x8D, 0x10);
624
625 LR(0x90);
626 LR(0x91);
627 LR(0x92);
628
629 LRP(0x9A);
630 LRP(0x9C);
631 LRP(0x9E);
632 LRP(0xA0);
633 LRP(0xA2);
634 LRP(0xA4);
635 LRP(0xA6);
636 LRP(0xA8);
637 LRP(0x98);
638 LRP(0xAE);
639 LRP(0x96);
640 LRP(0xAA);
641 LRP(0xAC);
642
643 LR(0xBE);
644 LR(0xC2);
645
646 maven_get_reg(c, 0x8D);
647 maven_set_reg(c, 0x8D, 0x04);
648
649 LR(0x20);
650 LR(0x22);
651 LR(0x93);
652 LR(0x20);
653 LR(0x22);
654 LR(0x25);
655 LRP(0x0E);
656 LRP(0x1E);
657 LRP(0x0E);
658 LRP(0x1E);
659
660
661 LR(0x83);
662 LR(0x84);
663 LR(0x85);
664 LR(0x86);
665 LR(0x87);
666 LR(0x88);
667 LR(0x89);
668 LR(0x8A);
669 LR(0x8B);
670
671 val = maven_get_reg(c, 0x8D);
672 val &= 0x14;
673 maven_set_reg(c, 0x8D, val);
674
675 LR(0x33);
676 LR(0x19);
677 LR(0x12);
678 LR(0x3B);
679 LR(0x13);
680 LR(0x39);
681 LR(0x1D);
682 LR(0x3A);
683 LR(0x24);
684 LR(0x14);
685 LR(0x15);
686 LR(0x16);
687 LRP(0x2D);
688 LRP(0x2F);
689 LR(0x1A);
690 LR(0x1B);
691 LR(0x1C);
692 LR(0x23);
693 LR(0x26);
694 LR(0x28);
695 LR(0x27);
696 LR(0x21);
697 LRP(0x2A);
698 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
699 maven_set_reg(c, 0x35, 0x1D);
700 else
701 maven_set_reg(c, 0x35, 0x1C);
702 LRP(0x3C);
703 LR(0x37);
704 LR(0x38);
705
706 maven_get_reg(c, 0xB0);
707 LR(0xB0);
708 LR(0x90);
709 LR(0xBE);
710 LR(0xC2);
711
712 LRP(0x9A);
713 LRP(0xA2);
714 LRP(0x9E);
715 LRP(0xA6);
716 LRP(0xAA);
717 LRP(0xAC);
718 maven_set_reg(c, 0x3E, 0x00);
719 maven_set_reg(c, 0x95, 0x20);
720}
721
722static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
723 struct mavenregs* m) {
724 unsigned int x;
725 unsigned int err = ~0;
726
727
728 m->regs[0x80] = 0x0F;
729 m->regs[0x81] = 0x07;
730 m->regs[0x82] = 0x81;
731
732 for (x = 0; x < 8; x++) {
733 unsigned int c;
734 unsigned int uninitialized_var(a), uninitialized_var(b),
735 uninitialized_var(h2);
736 unsigned int h = ht + 2 + x;
737
738 if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
739 unsigned int diff = h - h2;
740
741 if (diff < err) {
742 err = diff;
743 m->regs[0x80] = a - 1;
744 m->regs[0x81] = b - 1;
745 m->regs[0x82] = c | 0x80;
746 m->hcorr = h2 - 2;
747 m->htotal = h - 2;
748 }
749 }
750 }
751 return err != ~0U;
752}
753
754static inline int maven_compute_timming(struct maven_data* md,
755 struct my_timming* mt,
756 struct mavenregs* m) {
757 unsigned int tmpi;
758 unsigned int a, bv, c;
759 struct matrox_fb_info *minfo = md->primary_head;
760
761 m->mode = minfo->outputs[1].mode;
762 if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
763 unsigned int lmargin;
764 unsigned int umargin;
765 unsigned int vslen;
766 unsigned int hcrt;
767 unsigned int slen;
768
769 maven_init_TVdata(md, m);
770
771 if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
772 return -EINVAL;
773
774 lmargin = mt->HTotal - mt->HSyncEnd;
775 slen = mt->HSyncEnd - mt->HSyncStart;
776 hcrt = mt->HTotal - slen - mt->delay;
777 umargin = mt->VTotal - mt->VSyncEnd;
778 vslen = mt->VSyncEnd - mt->VSyncStart;
779
780 if (m->hcorr < mt->HTotal)
781 hcrt += m->hcorr;
782 if (hcrt > mt->HTotal)
783 hcrt -= mt->HTotal;
784 if (hcrt + 2 > mt->HTotal)
785 hcrt = 0;
786
787
788
789 m->regs[0x96] = m->hcorr;
790 m->regs[0x97] = m->hcorr >> 8;
791
792 m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
793
794 m->regs[0x9A] = lmargin;
795 m->regs[0x9B] = lmargin >> 8;
796
797 m->regs[0x9C] = 0x04;
798 m->regs[0x9D] = 0x00;
799
800 m->regs[0xA0] = m->htotal;
801 m->regs[0xA1] = m->htotal >> 8;
802
803 m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1;
804 m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
805
806 if (md->version == MGATVO_B) {
807 m->regs[0xA4] = 0x04;
808 m->regs[0xA5] = 0x00;
809 } else {
810 m->regs[0xA4] = 0x01;
811 m->regs[0xA5] = 0x00;
812 }
813
814 m->regs[0xA6] = 0x00;
815 m->regs[0xA7] = 0x00;
816
817 m->regs[0xA8] = mt->VTotal - 1;
818 m->regs[0xA9] = (mt->VTotal - 1) >> 8;
819
820 m->regs[0xAA] = hcrt;
821 m->regs[0xAB] = hcrt >> 8;
822
823 m->regs[0xAC] = mt->VTotal - 2;
824 m->regs[0xAD] = (mt->VTotal - 2) >> 8;
825
826 m->regs[0xAE] = 0x01;
827 m->regs[0xAF] = 0x00;
828 {
829 int hdec;
830 int hlen;
831 unsigned int ibmin = 4 + lmargin + mt->HDisplay;
832 unsigned int ib;
833 int i;
834
835
836
837 if (mt->HTotal)
838 hdec = 94208 / (mt->HTotal);
839 else
840 hdec = 0x81;
841 if (hdec > 0x81)
842 hdec = 0x81;
843 if (hdec < 0x41)
844 hdec = 0x41;
845 hdec--;
846 hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
847 if (hlen < 0)
848 hlen = 0;
849 hlen = hlen >> 8;
850 if (hlen > 0xFF)
851 hlen = 0xFF;
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867 i = 1;
868 do {
869 ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
870 i++;
871 } while (ib < ibmin);
872 if (ib >= m->htotal + 2) {
873 ib = ibmin;
874 }
875
876 m->regs[0x90] = hdec;
877 m->regs[0xC2] = hlen;
878
879 m->regs[0x9E] = ib;
880 m->regs[0x9F] = ib >> 8;
881 }
882 {
883 int vdec;
884 int vlen;
885
886#define MATROX_USE64BIT_DIVIDE
887 if (mt->VTotal) {
888#ifdef MATROX_USE64BIT_DIVIDE
889 u64 f1;
890 u32 a;
891 u32 b;
892
893 a = m->vlines * (m->htotal + 2);
894 b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
895
896 f1 = ((u64)a) << 15;
897 do_div(f1, b);
898 vdec = f1;
899#else
900 vdec = m->vlines * 32768 / mt->VTotal;
901#endif
902 } else
903 vdec = 0x8000;
904 if (vdec > 0x8000)
905 vdec = 0x8000;
906 vlen = (vslen + umargin + mt->VDisplay) * vdec;
907 vlen = (vlen >> 16) - 146;
908 if (vlen < 0)
909 vlen = 0;
910 if (vlen > 0xFF)
911 vlen = 0xFF;
912 vdec--;
913 m->regs[0x91] = vdec;
914 m->regs[0x92] = vdec >> 8;
915 m->regs[0xBE] = vlen;
916 }
917 m->regs[0xB0] = 0x08;
918 return 0;
919 }
920
921 DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
922 m->regs[0x80] = a;
923 m->regs[0x81] = bv;
924 m->regs[0x82] = c | 0x80;
925
926 m->regs[0xB3] = 0x01;
927 m->regs[0x94] = 0xB2;
928
929
930 m->regs[0x96] = mt->HTotal;
931 m->regs[0x97] = mt->HTotal >> 8;
932
933 m->regs[0x98] = 0x00;
934 m->regs[0x99] = 0x00;
935
936 tmpi = mt->HSyncEnd - mt->HSyncStart;
937 m->regs[0x9A] = tmpi;
938 m->regs[0x9B] = tmpi >> 8;
939
940 tmpi = mt->HTotal - mt->HSyncStart;
941 m->regs[0x9C] = tmpi;
942 m->regs[0x9D] = tmpi >> 8;
943
944 tmpi += mt->HDisplay;
945 m->regs[0x9E] = tmpi;
946 m->regs[0x9F] = tmpi >> 8;
947
948 tmpi = mt->HTotal + 1;
949 m->regs[0xA0] = tmpi;
950 m->regs[0xA1] = tmpi >> 8;
951
952 tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
953 m->regs[0xA2] = tmpi;
954 m->regs[0xA3] = tmpi >> 8;
955
956 tmpi = mt->VTotal - mt->VSyncStart;
957 m->regs[0xA4] = tmpi;
958 m->regs[0xA5] = tmpi >> 8;
959
960 tmpi = mt->VTotal - 1;
961 m->regs[0xA6] = tmpi;
962 m->regs[0xA7] = tmpi >> 8;
963
964 m->regs[0xA8] = tmpi;
965 m->regs[0xA9] = tmpi >> 8;
966
967 tmpi = mt->HTotal - mt->delay;
968 m->regs[0xAA] = tmpi;
969 m->regs[0xAB] = tmpi >> 8;
970
971 tmpi = mt->VTotal - 2;
972 m->regs[0xAC] = tmpi;
973 m->regs[0xAD] = tmpi >> 8;
974
975 m->regs[0xAE] = 0x00;
976 m->regs[0xAF] = 0x00;
977
978 m->regs[0xB0] = 0x03;
979 m->regs[0xB1] = 0xA0;
980 m->regs[0x8C] = 0x20;
981 m->regs[0x8D] = 0x04;
982 m->regs[0xB9] = 0x1A;
983 m->regs[0xBF] = 0x22;
984
985 return 0;
986}
987
988static int maven_program_timming(struct maven_data* md,
989 const struct mavenregs* m) {
990 struct i2c_client *c = md->client;
991
992 if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
993 LR(0x80);
994 LR(0x81);
995 LR(0x82);
996
997 LR(0xB3);
998 LR(0x94);
999
1000 LRP(0x96);
1001 LRP(0x98);
1002 LRP(0x9A);
1003 LRP(0x9C);
1004 LRP(0x9E);
1005 LRP(0xA0);
1006 LRP(0xA2);
1007 LRP(0xA4);
1008 LRP(0xA6);
1009 LRP(0xA8);
1010 LRP(0xAA);
1011 LRP(0xAC);
1012 LRP(0xAE);
1013
1014 LR(0xB0);
1015 LR(0xB1);
1016 LR(0x8C);
1017 LR(0x8D);
1018 LR(0xB9);
1019 LR(0xBF);
1020 } else {
1021 maven_init_TV(c, m);
1022 }
1023 return 0;
1024}
1025
1026static inline int maven_resync(struct maven_data* md) {
1027 struct i2c_client *c = md->client;
1028 maven_set_reg(c, 0x95, 0x20);
1029 return 0;
1030}
1031
1032static int maven_get_queryctrl (struct maven_data* md,
1033 struct v4l2_queryctrl *p) {
1034 int i;
1035
1036 i = get_ctrl_id(p->id);
1037 if (i >= 0) {
1038 *p = maven_controls[i].desc;
1039 return 0;
1040 }
1041 if (i == -ENOENT) {
1042 static const struct v4l2_queryctrl disctrl =
1043 { .flags = V4L2_CTRL_FLAG_DISABLED };
1044
1045 i = p->id;
1046 *p = disctrl;
1047 p->id = i;
1048 sprintf(p->name, "Ctrl #%08X", i);
1049 return 0;
1050 }
1051 return -EINVAL;
1052}
1053
1054static int maven_set_control (struct maven_data* md,
1055 struct v4l2_control *p) {
1056 int i;
1057
1058 i = get_ctrl_id(p->id);
1059 if (i < 0) return -EINVAL;
1060
1061
1062
1063
1064 if (p->value == *get_ctrl_ptr(md, i)) return 0;
1065
1066
1067
1068
1069 if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
1070 if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
1071
1072
1073
1074
1075 *get_ctrl_ptr(md, i) = p->value;
1076
1077 switch (p->id) {
1078 case V4L2_CID_BRIGHTNESS:
1079 case V4L2_CID_CONTRAST:
1080 {
1081 int blacklevel, whitelevel;
1082 maven_compute_bwlevel(md, &blacklevel, &whitelevel);
1083 blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
1084 whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
1085 maven_set_reg_pair(md->client, 0x0e, blacklevel);
1086 maven_set_reg_pair(md->client, 0x1e, whitelevel);
1087 }
1088 break;
1089 case V4L2_CID_SATURATION:
1090 {
1091 maven_set_reg(md->client, 0x20, p->value);
1092 maven_set_reg(md->client, 0x22, p->value);
1093 }
1094 break;
1095 case V4L2_CID_HUE:
1096 {
1097 maven_set_reg(md->client, 0x25, p->value);
1098 }
1099 break;
1100 case V4L2_CID_GAMMA:
1101 {
1102 const struct maven_gamma* g;
1103 g = maven_compute_gamma(md);
1104 maven_set_reg(md->client, 0x83, g->reg83);
1105 maven_set_reg(md->client, 0x84, g->reg84);
1106 maven_set_reg(md->client, 0x85, g->reg85);
1107 maven_set_reg(md->client, 0x86, g->reg86);
1108 maven_set_reg(md->client, 0x87, g->reg87);
1109 maven_set_reg(md->client, 0x88, g->reg88);
1110 maven_set_reg(md->client, 0x89, g->reg89);
1111 maven_set_reg(md->client, 0x8a, g->reg8a);
1112 maven_set_reg(md->client, 0x8b, g->reg8b);
1113 }
1114 break;
1115 case MATROXFB_CID_TESTOUT:
1116 {
1117 unsigned char val
1118 = maven_get_reg(md->client, 0x8d);
1119 if (p->value) val |= 0x10;
1120 else val &= ~0x10;
1121 maven_set_reg(md->client, 0x8d, val);
1122 }
1123 break;
1124 case MATROXFB_CID_DEFLICKER:
1125 {
1126 maven_set_reg(md->client, 0x93, maven_compute_deflicker(md));
1127 }
1128 break;
1129 }
1130
1131
1132 return 0;
1133}
1134
1135static int maven_get_control (struct maven_data* md,
1136 struct v4l2_control *p) {
1137 int i;
1138
1139 i = get_ctrl_id(p->id);
1140 if (i < 0) return -EINVAL;
1141 p->value = *get_ctrl_ptr(md, i);
1142 return 0;
1143}
1144
1145
1146
1147static int maven_out_compute(void* md, struct my_timming* mt) {
1148#define mdinfo ((struct maven_data*)md)
1149#define minfo (mdinfo->primary_head)
1150 return maven_compute_timming(md, mt, &minfo->hw.maven);
1151#undef minfo
1152#undef mdinfo
1153}
1154
1155static int maven_out_program(void* md) {
1156#define mdinfo ((struct maven_data*)md)
1157#define minfo (mdinfo->primary_head)
1158 return maven_program_timming(md, &minfo->hw.maven);
1159#undef minfo
1160#undef mdinfo
1161}
1162
1163static int maven_out_start(void* md) {
1164 return maven_resync(md);
1165}
1166
1167static int maven_out_verify_mode(void* md, u_int32_t arg) {
1168 switch (arg) {
1169 case MATROXFB_OUTPUT_MODE_PAL:
1170 case MATROXFB_OUTPUT_MODE_NTSC:
1171 case MATROXFB_OUTPUT_MODE_MONITOR:
1172 return 0;
1173 }
1174 return -EINVAL;
1175}
1176
1177static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) {
1178 return maven_get_queryctrl(md, p);
1179}
1180
1181static int maven_out_get_ctrl(void* md, struct v4l2_control* p) {
1182 return maven_get_control(md, p);
1183}
1184
1185static int maven_out_set_ctrl(void* md, struct v4l2_control* p) {
1186 return maven_set_control(md, p);
1187}
1188
1189static struct matrox_altout maven_altout = {
1190 .name = "Secondary output",
1191 .compute = maven_out_compute,
1192 .program = maven_out_program,
1193 .start = maven_out_start,
1194 .verifymode = maven_out_verify_mode,
1195 .getqueryctrl = maven_out_get_queryctrl,
1196 .getctrl = maven_out_get_ctrl,
1197 .setctrl = maven_out_set_ctrl,
1198};
1199
1200static int maven_init_client(struct i2c_client* clnt) {
1201 struct maven_data* md = i2c_get_clientdata(clnt);
1202 struct matrox_fb_info *minfo = container_of(clnt->adapter,
1203 struct i2c_bit_adapter,
1204 adapter)->minfo;
1205
1206 md->primary_head = minfo;
1207 md->client = clnt;
1208 down_write(&minfo->altout.lock);
1209 minfo->outputs[1].output = &maven_altout;
1210 minfo->outputs[1].src = minfo->outputs[1].default_src;
1211 minfo->outputs[1].data = md;
1212 minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
1213 up_write(&minfo->altout.lock);
1214 if (maven_get_reg(clnt, 0xB2) < 0x14) {
1215 md->version = MGATVO_B;
1216
1217 } else {
1218 md->version = MGATVO_C;
1219 }
1220
1221
1222
1223 {
1224 unsigned int i;
1225
1226 for (i = 0; i < MAVCTRLS; ++i) {
1227 *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
1228 }
1229 }
1230
1231 return 0;
1232}
1233
1234static int maven_shutdown_client(struct i2c_client* clnt) {
1235 struct maven_data* md = i2c_get_clientdata(clnt);
1236
1237 if (md->primary_head) {
1238 struct matrox_fb_info *minfo = md->primary_head;
1239
1240 down_write(&minfo->altout.lock);
1241 minfo->outputs[1].src = MATROXFB_SRC_NONE;
1242 minfo->outputs[1].output = NULL;
1243 minfo->outputs[1].data = NULL;
1244 minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
1245 up_write(&minfo->altout.lock);
1246 md->primary_head = NULL;
1247 }
1248 return 0;
1249}
1250
1251static int maven_probe(struct i2c_client *client,
1252 const struct i2c_device_id *id)
1253{
1254 struct i2c_adapter *adapter = client->adapter;
1255 int err = -ENODEV;
1256 struct maven_data* data;
1257
1258 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
1259 I2C_FUNC_SMBUS_BYTE_DATA |
1260 I2C_FUNC_NOSTART |
1261 I2C_FUNC_PROTOCOL_MANGLING))
1262 goto ERROR0;
1263 if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
1264 err = -ENOMEM;
1265 goto ERROR0;
1266 }
1267 i2c_set_clientdata(client, data);
1268 err = maven_init_client(client);
1269 if (err)
1270 goto ERROR4;
1271 return 0;
1272ERROR4:;
1273 kfree(data);
1274ERROR0:;
1275 return err;
1276}
1277
1278static int maven_remove(struct i2c_client *client)
1279{
1280 maven_shutdown_client(client);
1281 kfree(i2c_get_clientdata(client));
1282 return 0;
1283}
1284
1285static const struct i2c_device_id maven_id[] = {
1286 { "maven", 0 },
1287 { }
1288};
1289MODULE_DEVICE_TABLE(i2c, maven_id);
1290
1291static struct i2c_driver maven_driver={
1292 .driver = {
1293 .name = "maven",
1294 },
1295 .probe = maven_probe,
1296 .remove = maven_remove,
1297 .id_table = maven_id,
1298};
1299
1300module_i2c_driver(maven_driver);
1301MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1302MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1303MODULE_LICENSE("GPL");
1304