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