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