3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
5 * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
7 * Portions Copyright (c) 2001 Matrox Graphics Inc.
9 * Version: 1.65 2002/08/14
11 * See matroxfb_base.c for contributors.
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 <asm/div64.h>
25 static const struct maven_gamma {
36 { 131, 57, 223, 15, 117, 212, 251, 91, 156},
37 { 133, 61, 128, 63, 180, 147, 195, 100, 180},
38 { 131, 19, 63, 31, 50, 66, 171, 64, 176},
39 { 0, 0, 0, 31, 16, 16, 16, 100, 200},
40 { 8, 23, 47, 73, 147, 244, 220, 80, 195},
41 { 22, 43, 64, 80, 147, 115, 58, 85, 168},
42 { 34, 60, 80, 214, 147, 212, 188, 85, 167},
43 { 45, 77, 96, 216, 147, 99, 91, 85, 159},
44 { 56, 76, 112, 107, 147, 212, 148, 64, 144},
45 { 65, 91, 128, 137, 147, 196, 17, 69, 148},
46 { 72, 104, 136, 138, 147, 180, 245, 73, 147},
47 { 87, 116, 143, 126, 16, 83, 229, 77, 144},
48 { 95, 119, 152, 254, 244, 83, 221, 77, 151},
49 { 100, 129, 159, 156, 244, 148, 197, 77, 160},
50 { 105, 141, 167, 247, 244, 132, 181, 84, 166},
51 { 105, 147, 168, 247, 244, 245, 181, 90, 170},
52 { 120, 153, 175, 248, 212, 229, 165, 90, 180},
53 { 119, 156, 176, 248, 244, 229, 84, 74, 160},
54 { 119, 158, 183, 248, 244, 229, 149, 78, 165}
57 /* Definition of the various controls */
59 struct v4l2_queryctrl desc;
66 static const struct mctl maven_controls[] =
67 { { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
69 0, WLMAX - BLMIN, 1, 379 - BLMIN,
71 }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
72 { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
76 }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
77 { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
81 }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
82 { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
86 }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
87 { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER,
89 0, ARRAY_SIZE(maven_gamma) - 1, 1, 3,
91 }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
92 { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
96 }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
97 { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER,
101 }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
105 #define MAVCTRLS ARRAY_SIZE(maven_controls)
107 /* Return: positive number: id found
108 -EINVAL: id not found, return failure
109 -ENOENT: id not found, create fake disabled control */
110 static int get_ctrl_id(__u32 v4l2_id) {
113 for (i = 0; i < MAVCTRLS; i++) {
114 if (v4l2_id < maven_controls[i].desc.id) {
115 if (maven_controls[i].desc.id == 0x08000000) {
120 if (v4l2_id == maven_controls[i].desc.id) {
128 struct matrox_fb_info* primary_head;
129 struct i2c_client *client;
133 static int* get_ctrl_ptr(struct maven_data* md, int idx) {
134 return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
137 static int maven_get_reg(struct i2c_client* c, char reg) {
139 struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® },
140 { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }};
143 err = i2c_transfer(c->adapter, msgs, 2);
145 printk(KERN_INFO "ReadReg(%d) failed\n", reg);
149 static int maven_set_reg(struct i2c_client* c, int reg, int val) {
152 err = i2c_smbus_write_byte_data(c, reg, val);
154 printk(KERN_INFO "WriteReg(%d) failed\n", reg);
158 static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
161 err = i2c_smbus_write_word_data(c, reg, val);
163 printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
167 static const struct matrox_pll_features maven_pll = {
175 struct matrox_pll_features2 {
176 unsigned int vco_freq_min;
177 unsigned int vco_freq_max;
178 unsigned int feed_div_min;
179 unsigned int feed_div_max;
180 unsigned int in_div_min;
181 unsigned int in_div_max;
182 unsigned int post_shift_max;
185 struct matrox_pll_ctl {
186 unsigned int ref_freq;
190 static const struct matrox_pll_features2 maven1000_pll = {
198 static const struct matrox_pll_ctl maven_PAL = {
203 static const struct matrox_pll_ctl maven_NTSC = {
204 450450, /* 27027000/60 == 27000000/59.94005994 */
208 static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
209 const struct matrox_pll_ctl* ctl,
210 unsigned int htotal, unsigned int vtotal,
211 unsigned int* in, unsigned int* feed, unsigned int* post,
213 unsigned int besth2 = 0;
214 unsigned int fxtal = ctl->ref_freq;
215 unsigned int fmin = pll->vco_freq_min / ctl->den;
223 scrlen = htotal * (vtotal - 1);
224 fwant = htotal * vtotal;
225 fmax = pll->vco_freq_max / ctl->den;
227 dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
228 fwant, fxtal, htotal, vtotal, fmax);
229 for (p = 1; p <= pll->post_shift_max; p++) {
230 if (fwant * 2 > fmax)
236 for (; p-- > 0; fwant >>= 1) {
239 if (fwant < fmin) break;
240 for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
245 n = (fwant * m) / fxtal;
246 if (n < pll->feed_div_min)
248 if (n > pll->feed_div_max)
263 dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
265 dprintk(KERN_DEBUG "Better...\n");
274 /* if h2/post/in/feed have not been assigned, return zero (error) */
278 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
279 return fxtal * (*feed) / (*in) * ctl->den;
282 static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
283 unsigned int htotal, unsigned int vtotal,
284 unsigned int* in, unsigned int* feed, unsigned int* post,
285 unsigned int* htotal2) {
287 unsigned int uninitialized_var(p);
289 fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
293 if (fvco <= 100000000)
295 else if (fvco <= 140000000)
297 else if (fvco <= 180000000)
305 static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
306 unsigned int* in, unsigned int* feed, unsigned int* post) {
310 fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
314 else if (fvco <= 140000)
316 else if (fvco <= 180000)
324 static unsigned char maven_compute_deflicker (const struct maven_data* md) {
327 df = (md->version == MGATVO_B?0x40:0x00);
328 switch (md->primary_head->altout.tvo_params.deflicker) {
342 static void maven_compute_bwlevel (const struct maven_data* md,
344 const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
345 const int c = md->primary_head->altout.tvo_params.contrast;
347 *bl = max(b - c, BLMIN);
348 *wl = min(b + c, WLMAX);
351 static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
352 return maven_gamma + md->primary_head->altout.tvo_params.gamma;
356 static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
357 static struct mavenregs palregs = { {
358 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
360 0x00, /* ? not written */
361 0x00, /* modified by code (F9 written...) */
362 0x00, /* ? not written */
368 0x00, /* ? not written */
369 0x3F, 0x03, /* 0E-0F */
370 0x3F, 0x03, /* 10-11 */
373 0x1C, 0x3D, 0x14, /* 14-16 */
374 0x9C, 0x01, /* 17-18 */
380 0x89, 0x03, /* 1E-1F */
391 0x55, 0x01, /* 2A-2B */
393 0x07, 0x7E, /* 2D-2E */
394 0x02, 0x54, /* 2F-30 */
395 0xB0, 0x00, /* 31-32 */
398 0x00, /* 35 written multiple times */
399 0x00, /* 36 not written */
405 0x3F, 0x03, /* 3C-3D */
406 0x00, /* 3E written multiple times */
407 0x00, /* 3F not written */
408 }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
409 static struct mavenregs ntscregs = { {
410 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
412 0x00, /* ? not written */
413 0x00, /* modified by code (F9 written...) */
414 0x00, /* ? not written */
420 0x00, /* ? not written */
421 0x41, 0x00, /* 0E-0F */
422 0x3C, 0x00, /* 10-11 */
425 0x1B, 0x1B, 0x24, /* 14-16 */
426 0x83, 0x01, /* 17-18 */
432 0x89, 0x02, /* 1E-1F */
443 0xFF, 0x03, /* 2A-2B */
445 0x0F, 0x78, /* 2D-2E */
446 0x00, 0x00, /* 2F-30 */
447 0xB2, 0x04, /* 31-32 */
450 0x00, /* 35 written multiple times */
451 0x00, /* 36 not written */
457 0x3C, 0x00, /* 3C-3D */
458 0x00, /* 3E written multiple times */
459 0x00, /* never written */
460 }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
461 MINFO_FROM(md->primary_head);
463 if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_PAL)
469 data->regs[0x93] = maven_compute_deflicker(md);
473 const struct maven_gamma* g;
474 g = maven_compute_gamma(md);
475 data->regs[0x83] = g->reg83;
476 data->regs[0x84] = g->reg84;
477 data->regs[0x85] = g->reg85;
478 data->regs[0x86] = g->reg86;
479 data->regs[0x87] = g->reg87;
480 data->regs[0x88] = g->reg88;
481 data->regs[0x89] = g->reg89;
482 data->regs[0x8A] = g->reg8a;
483 data->regs[0x8B] = g->reg8b;
486 /* Set contrast / brightness */
489 maven_compute_bwlevel (md, &bl, &wl);
490 data->regs[0x0e] = bl >> 2;
491 data->regs[0x0f] = bl & 3;
492 data->regs[0x1e] = wl >> 2;
493 data->regs[0x1f] = wl & 3;
499 data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
503 data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
507 #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
508 #define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
509 static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
513 maven_set_reg(c, 0x3E, 0x01);
514 maven_get_reg(c, 0x82); /* fetch oscillator state? */
515 maven_set_reg(c, 0x8C, 0x00);
516 maven_get_reg(c, 0x94); /* get 0x82 */
517 maven_set_reg(c, 0x94, 0xA2);
520 maven_set_reg_pair(c, 0x8E, 0x1EFF);
521 maven_set_reg(c, 0xC6, 0x01);
523 /* removed code... */
525 maven_get_reg(c, 0x06);
526 maven_set_reg(c, 0x06, 0xF9); /* or read |= 0xF0 ? */
528 /* removed code here... */
530 /* real code begins here? */
531 /* chroma subcarrier */
532 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
545 if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
546 maven_set_reg(c, 0x35, 0x10); /* ... */
548 maven_set_reg(c, 0x35, 0x0F); /* ... */
556 LR(0x20); /* saturation #1 */
557 LR(0x22); /* saturation #2 */
583 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
584 maven_set_reg(c, 0x35, 0x1D); /* ... */
586 maven_set_reg(c, 0x35, 0x1C);
591 maven_set_reg(c, 0xB3, 0x01);
593 maven_get_reg(c, 0xB0); /* read 0x80 */
594 maven_set_reg(c, 0xB0, 0x08); /* ugh... */
595 maven_get_reg(c, 0xB9); /* read 0x7C */
596 maven_set_reg(c, 0xB9, 0x78);
597 maven_get_reg(c, 0xBF); /* read 0x00 */
598 maven_set_reg(c, 0xBF, 0x02);
599 maven_get_reg(c, 0x94); /* read 0x82 */
600 maven_set_reg(c, 0x94, 0xB3);
602 LR(0x80); /* 04 1A 91 or 05 21 91 */
606 maven_set_reg(c, 0x8C, 0x20);
607 maven_get_reg(c, 0x8D);
608 maven_set_reg(c, 0x8D, 0x10);
610 LR(0x90); /* 4D 50 52 or 4E 05 45 */
614 LRP(0x9A); /* 0049 or 004F */
615 LRP(0x9C); /* 0004 or 0004 */
616 LRP(0x9E); /* 0458 or 045E */
617 LRP(0xA0); /* 05DA or 051B */
618 LRP(0xA2); /* 00CC or 00CF */
619 LRP(0xA4); /* 007D or 007F */
620 LRP(0xA6); /* 007C or 007E */
621 LRP(0xA8); /* 03CB or 03CE */
622 LRP(0x98); /* 0000 or 0000 */
623 LRP(0xAE); /* 0044 or 003A */
624 LRP(0x96); /* 05DA or 051B */
625 LRP(0xAA); /* 04BC or 046A */
626 LRP(0xAC); /* 004D or 004E */
631 maven_get_reg(c, 0x8D);
632 maven_set_reg(c, 0x8D, 0x04);
634 LR(0x20); /* saturation #1 */
635 LR(0x22); /* saturation #2 */
636 LR(0x93); /* whoops */
637 LR(0x20); /* oh, saturation #1 again */
638 LR(0x22); /* oh, saturation #2 again */
642 LRP(0x0E); /* problems with memory? */
643 LRP(0x1E); /* yes, matrox must have problems in memory area... */
645 /* load gamma correction stuff */
656 val = maven_get_reg(c, 0x8D);
657 val &= 0x14; /* 0x10 or anything ored with it */
658 maven_set_reg(c, 0x8D, val);
683 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
684 maven_set_reg(c, 0x35, 0x1D);
686 maven_set_reg(c, 0x35, 0x1C);
691 maven_get_reg(c, 0xB0);
692 LR(0xB0); /* output mode */
703 maven_set_reg(c, 0x3E, 0x00);
704 maven_set_reg(c, 0x95, 0x20);
707 static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
708 struct mavenregs* m) {
710 unsigned int err = ~0;
713 m->regs[0x80] = 0x0F;
714 m->regs[0x81] = 0x07;
715 m->regs[0x82] = 0x81;
717 for (x = 0; x < 8; x++) {
719 unsigned int uninitialized_var(a), uninitialized_var(b),
720 uninitialized_var(h2);
721 unsigned int h = ht + 2 + x;
723 if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
724 unsigned int diff = h - h2;
728 m->regs[0x80] = a - 1;
729 m->regs[0x81] = b - 1;
730 m->regs[0x82] = c | 0x80;
739 static inline int maven_compute_timming(struct maven_data* md,
740 struct my_timming* mt,
741 struct mavenregs* m) {
743 unsigned int a, bv, c;
744 MINFO_FROM(md->primary_head);
746 m->mode = ACCESS_FBINFO(outputs[1]).mode;
747 if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
748 unsigned int lmargin;
749 unsigned int umargin;
754 maven_init_TVdata(md, m);
756 if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
759 lmargin = mt->HTotal - mt->HSyncEnd;
760 slen = mt->HSyncEnd - mt->HSyncStart;
761 hcrt = mt->HTotal - slen - mt->delay;
762 umargin = mt->VTotal - mt->VSyncEnd;
763 vslen = mt->VSyncEnd - mt->VSyncStart;
765 if (m->hcorr < mt->HTotal)
767 if (hcrt > mt->HTotal)
769 if (hcrt + 2 > mt->HTotal)
770 hcrt = 0; /* or issue warning? */
772 /* last (first? middle?) line in picture can have different length */
774 m->regs[0x96] = m->hcorr;
775 m->regs[0x97] = m->hcorr >> 8;
777 m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
779 m->regs[0x9A] = lmargin; /* 100% */
780 m->regs[0x9B] = lmargin >> 8; /* 100% */
782 m->regs[0x9C] = 0x04;
783 m->regs[0x9D] = 0x00;
785 m->regs[0xA0] = m->htotal;
786 m->regs[0xA1] = m->htotal >> 8;
788 m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */
789 m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
790 /* something end... [A6]+1..[A8] */
791 if (md->version == MGATVO_B) {
792 m->regs[0xA4] = 0x04;
793 m->regs[0xA5] = 0x00;
795 m->regs[0xA4] = 0x01;
796 m->regs[0xA5] = 0x00;
798 /* something start... 0..[A4]-1 */
799 m->regs[0xA6] = 0x00;
800 m->regs[0xA7] = 0x00;
801 /* vertical line count - 1 */
802 m->regs[0xA8] = mt->VTotal - 1;
803 m->regs[0xA9] = (mt->VTotal - 1) >> 8;
804 /* horizontal vidrst pos */
805 m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */
806 m->regs[0xAB] = hcrt >> 8;
807 /* vertical vidrst pos */
808 m->regs[0xAC] = mt->VTotal - 2;
809 m->regs[0xAD] = (mt->VTotal - 2) >> 8;
810 /* moves picture up/down and so on... */
811 m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
812 m->regs[0xAF] = 0x00;
816 unsigned int ibmin = 4 + lmargin + mt->HDisplay;
821 /* Where 94208 came from? */
823 hdec = 94208 / (mt->HTotal);
831 hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
837 /* Now we have to compute input buffer length.
838 If you want any picture, it must be between
842 If you want perfect picture even on the top
843 of screen, it must be also
844 0x3C0000 * i / hdec + Q - R / hdec
854 ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
856 } while (ib < ibmin);
857 if (ib >= m->htotal + 2) {
861 m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
862 m->regs[0xC2] = hlen;
863 /* 'valid' input line length */
865 m->regs[0x9F] = ib >> 8;
871 #define MATROX_USE64BIT_DIVIDE
873 #ifdef MATROX_USE64BIT_DIVIDE
878 a = m->vlines * (m->htotal + 2);
879 b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
881 f1 = ((u64)a) << 15; /* *32768 */
885 vdec = m->vlines * 32768 / mt->VTotal;
891 vlen = (vslen + umargin + mt->VDisplay) * vdec;
892 vlen = (vlen >> 16) - 146; /* FIXME: 146?! */
898 m->regs[0x91] = vdec;
899 m->regs[0x92] = vdec >> 8;
900 m->regs[0xBE] = vlen;
902 m->regs[0xB0] = 0x08; /* output: SVideo/Composite */
906 DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
909 m->regs[0x82] = c | 0x80;
911 m->regs[0xB3] = 0x01;
912 m->regs[0x94] = 0xB2;
915 m->regs[0x96] = mt->HTotal;
916 m->regs[0x97] = mt->HTotal >> 8;
918 m->regs[0x98] = 0x00;
919 m->regs[0x99] = 0x00;
921 tmpi = mt->HSyncEnd - mt->HSyncStart;
922 m->regs[0x9A] = tmpi;
923 m->regs[0x9B] = tmpi >> 8;
925 tmpi = mt->HTotal - mt->HSyncStart;
926 m->regs[0x9C] = tmpi;
927 m->regs[0x9D] = tmpi >> 8;
929 tmpi += mt->HDisplay;
930 m->regs[0x9E] = tmpi;
931 m->regs[0x9F] = tmpi >> 8;
933 tmpi = mt->HTotal + 1;
934 m->regs[0xA0] = tmpi;
935 m->regs[0xA1] = tmpi >> 8;
937 tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
938 m->regs[0xA2] = tmpi;
939 m->regs[0xA3] = tmpi >> 8;
941 tmpi = mt->VTotal - mt->VSyncStart;
942 m->regs[0xA4] = tmpi;
943 m->regs[0xA5] = tmpi >> 8;
945 tmpi = mt->VTotal - 1;
946 m->regs[0xA6] = tmpi;
947 m->regs[0xA7] = tmpi >> 8;
949 m->regs[0xA8] = tmpi;
950 m->regs[0xA9] = tmpi >> 8;
952 tmpi = mt->HTotal - mt->delay;
953 m->regs[0xAA] = tmpi;
954 m->regs[0xAB] = tmpi >> 8;
956 tmpi = mt->VTotal - 2;
957 m->regs[0xAC] = tmpi;
958 m->regs[0xAD] = tmpi >> 8;
960 m->regs[0xAE] = 0x00;
961 m->regs[0xAF] = 0x00;
963 m->regs[0xB0] = 0x03; /* output: monitor */
964 m->regs[0xB1] = 0xA0; /* ??? */
965 m->regs[0x8C] = 0x20; /* must be set... */
966 m->regs[0x8D] = 0x04; /* defaults to 0x10: test signal */
967 m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
968 m->regs[0xBF] = 0x22; /* makes picture stable */
973 static int maven_program_timming(struct maven_data* md,
974 const struct mavenregs* m) {
975 struct i2c_client *c = md->client;
977 if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
999 LR(0xB0); /* output: monitor */
1001 LR(0x8C); /* must be set... */
1002 LR(0x8D); /* defaults to 0x10: test signal */
1003 LR(0xB9); /* defaults to 0x2C: too bright */
1004 LR(0xBF); /* makes picture stable */
1006 maven_init_TV(c, m);
1011 static inline int maven_resync(struct maven_data* md) {
1012 struct i2c_client *c = md->client;
1013 maven_set_reg(c, 0x95, 0x20); /* start whole thing */
1017 static int maven_get_queryctrl (struct maven_data* md,
1018 struct v4l2_queryctrl *p) {
1021 i = get_ctrl_id(p->id);
1023 *p = maven_controls[i].desc;
1027 static const struct v4l2_queryctrl disctrl =
1028 { .flags = V4L2_CTRL_FLAG_DISABLED };
1033 sprintf(p->name, "Ctrl #%08X", i);
1039 static int maven_set_control (struct maven_data* md,
1040 struct v4l2_control *p) {
1043 i = get_ctrl_id(p->id);
1044 if (i < 0) return -EINVAL;
1049 if (p->value == *get_ctrl_ptr(md, i)) return 0;
1054 if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
1055 if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
1060 *get_ctrl_ptr(md, i) = p->value;
1063 case V4L2_CID_BRIGHTNESS:
1064 case V4L2_CID_CONTRAST:
1066 int blacklevel, whitelevel;
1067 maven_compute_bwlevel(md, &blacklevel, &whitelevel);
1068 blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
1069 whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
1070 maven_set_reg_pair(md->client, 0x0e, blacklevel);
1071 maven_set_reg_pair(md->client, 0x1e, whitelevel);
1074 case V4L2_CID_SATURATION:
1076 maven_set_reg(md->client, 0x20, p->value);
1077 maven_set_reg(md->client, 0x22, p->value);
1082 maven_set_reg(md->client, 0x25, p->value);
1085 case V4L2_CID_GAMMA:
1087 const struct maven_gamma* g;
1088 g = maven_compute_gamma(md);
1089 maven_set_reg(md->client, 0x83, g->reg83);
1090 maven_set_reg(md->client, 0x84, g->reg84);
1091 maven_set_reg(md->client, 0x85, g->reg85);
1092 maven_set_reg(md->client, 0x86, g->reg86);
1093 maven_set_reg(md->client, 0x87, g->reg87);
1094 maven_set_reg(md->client, 0x88, g->reg88);
1095 maven_set_reg(md->client, 0x89, g->reg89);
1096 maven_set_reg(md->client, 0x8a, g->reg8a);
1097 maven_set_reg(md->client, 0x8b, g->reg8b);
1100 case MATROXFB_CID_TESTOUT:
1103 = maven_get_reg(md->client, 0x8d);
1104 if (p->value) val |= 0x10;
1106 maven_set_reg(md->client, 0x8d, val);
1109 case MATROXFB_CID_DEFLICKER:
1111 maven_set_reg(md->client, 0x93, maven_compute_deflicker(md));
1120 static int maven_get_control (struct maven_data* md,
1121 struct v4l2_control *p) {
1124 i = get_ctrl_id(p->id);
1125 if (i < 0) return -EINVAL;
1126 p->value = *get_ctrl_ptr(md, i);
1130 /******************************************************/
1132 static int maven_out_compute(void* md, struct my_timming* mt) {
1133 #define mdinfo ((struct maven_data*)md)
1134 #define minfo (mdinfo->primary_head)
1135 return maven_compute_timming(md, mt, &ACCESS_FBINFO(hw).maven);
1140 static int maven_out_program(void* md) {
1141 #define mdinfo ((struct maven_data*)md)
1142 #define minfo (mdinfo->primary_head)
1143 return maven_program_timming(md, &ACCESS_FBINFO(hw).maven);
1148 static int maven_out_start(void* md) {
1149 return maven_resync(md);
1152 static int maven_out_verify_mode(void* md, u_int32_t arg) {
1154 case MATROXFB_OUTPUT_MODE_PAL:
1155 case MATROXFB_OUTPUT_MODE_NTSC:
1156 case MATROXFB_OUTPUT_MODE_MONITOR:
1162 static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) {
1163 return maven_get_queryctrl(md, p);
1166 static int maven_out_get_ctrl(void* md, struct v4l2_control* p) {
1167 return maven_get_control(md, p);
1170 static int maven_out_set_ctrl(void* md, struct v4l2_control* p) {
1171 return maven_set_control(md, p);
1174 static struct matrox_altout maven_altout = {
1175 .name = "Secondary output",
1176 .compute = maven_out_compute,
1177 .program = maven_out_program,
1178 .start = maven_out_start,
1179 .verifymode = maven_out_verify_mode,
1180 .getqueryctrl = maven_out_get_queryctrl,
1181 .getctrl = maven_out_get_ctrl,
1182 .setctrl = maven_out_set_ctrl,
1185 static int maven_init_client(struct i2c_client* clnt) {
1186 struct maven_data* md = i2c_get_clientdata(clnt);
1187 MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo);
1189 md->primary_head = MINFO;
1191 down_write(&ACCESS_FBINFO(altout.lock));
1192 ACCESS_FBINFO(outputs[1]).output = &maven_altout;
1193 ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
1194 ACCESS_FBINFO(outputs[1]).data = md;
1195 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1196 up_write(&ACCESS_FBINFO(altout.lock));
1197 if (maven_get_reg(clnt, 0xB2) < 0x14) {
1198 md->version = MGATVO_B;
1199 /* Tweak some things for this old chip */
1201 md->version = MGATVO_C;
1204 * Set all parameters to its initial values.
1209 for (i = 0; i < MAVCTRLS; ++i) {
1210 *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
1217 static int maven_shutdown_client(struct i2c_client* clnt) {
1218 struct maven_data* md = i2c_get_clientdata(clnt);
1220 if (md->primary_head) {
1221 MINFO_FROM(md->primary_head);
1223 down_write(&ACCESS_FBINFO(altout.lock));
1224 ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
1225 ACCESS_FBINFO(outputs[1]).output = NULL;
1226 ACCESS_FBINFO(outputs[1]).data = NULL;
1227 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1228 up_write(&ACCESS_FBINFO(altout.lock));
1229 md->primary_head = NULL;
1234 static int maven_probe(struct i2c_client *client,
1235 const struct i2c_device_id *id)
1237 struct i2c_adapter *adapter = client->adapter;
1239 struct maven_data* data;
1241 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
1242 I2C_FUNC_SMBUS_BYTE_DATA |
1243 I2C_FUNC_PROTOCOL_MANGLING))
1245 if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
1249 i2c_set_clientdata(client, data);
1250 err = maven_init_client(client);
1260 static int maven_remove(struct i2c_client *client)
1262 maven_shutdown_client(client);
1263 kfree(i2c_get_clientdata(client));
1267 static const struct i2c_device_id maven_id[] = {
1271 MODULE_DEVICE_TABLE(i2c, maven_id);
1273 static struct i2c_driver maven_driver={
1277 .probe = maven_probe,
1278 .remove = maven_remove,
1279 .id_table = maven_id,
1282 static int __init matroxfb_maven_init(void)
1284 return i2c_add_driver(&maven_driver);
1287 static void __exit matroxfb_maven_exit(void)
1289 i2c_del_driver(&maven_driver);
1292 MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1293 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1294 MODULE_LICENSE("GPL");
1295 module_init(matroxfb_maven_init);
1296 module_exit(matroxfb_maven_exit);
1297 /* we do not have __setup() yet */