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>
22 #define MAVEN_I2CID (0x1B)
27 static const struct 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}
59 /* Definition of the various controls */
61 struct v4l2_queryctrl desc;
68 static const struct mctl maven_controls[] =
69 { { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
71 0, WLMAX - BLMIN, 1, 379 - BLMIN,
73 }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
74 { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
78 }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
79 { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
83 }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
84 { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
88 }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
89 { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER,
91 0, ARRAY_SIZE(maven_gamma) - 1, 1, 3,
93 }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
94 { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
98 }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
99 { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER,
103 }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
107 #define MAVCTRLS ARRAY_SIZE(maven_controls)
109 /* Return: positive number: id found
110 -EINVAL: id not found, return failure
111 -ENOENT: id not found, create fake disabled control */
112 static int get_ctrl_id(__u32 v4l2_id) {
115 for (i = 0; i < MAVCTRLS; i++) {
116 if (v4l2_id < maven_controls[i].desc.id) {
117 if (maven_controls[i].desc.id == 0x08000000) {
122 if (v4l2_id == maven_controls[i].desc.id) {
130 struct matrox_fb_info* primary_head;
131 struct i2c_client client;
135 static int* get_ctrl_ptr(struct maven_data* md, int idx) {
136 return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
139 static int maven_get_reg(struct i2c_client* c, char reg) {
141 struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® },
142 { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }};
145 err = i2c_transfer(c->adapter, msgs, 2);
147 printk(KERN_INFO "ReadReg(%d) failed\n", reg);
151 static int maven_set_reg(struct i2c_client* c, int reg, int val) {
154 err = i2c_smbus_write_byte_data(c, reg, val);
156 printk(KERN_INFO "WriteReg(%d) failed\n", reg);
160 static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
163 err = i2c_smbus_write_word_data(c, reg, val);
165 printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
169 static const struct matrox_pll_features maven_pll = {
177 struct matrox_pll_features2 {
178 unsigned int vco_freq_min;
179 unsigned int vco_freq_max;
180 unsigned int feed_div_min;
181 unsigned int feed_div_max;
182 unsigned int in_div_min;
183 unsigned int in_div_max;
184 unsigned int post_shift_max;
187 struct matrox_pll_ctl {
188 unsigned int ref_freq;
192 static const struct matrox_pll_features2 maven1000_pll = {
200 static const struct matrox_pll_ctl maven_PAL = {
205 static const struct matrox_pll_ctl maven_NTSC = {
206 450450, /* 27027000/60 == 27000000/59.94005994 */
210 static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
211 const struct matrox_pll_ctl* ctl,
212 unsigned int htotal, unsigned int vtotal,
213 unsigned int* in, unsigned int* feed, unsigned int* post,
215 unsigned int besth2 = 0;
216 unsigned int fxtal = ctl->ref_freq;
217 unsigned int fmin = pll->vco_freq_min / ctl->den;
225 scrlen = htotal * (vtotal - 1);
226 fwant = htotal * vtotal;
227 fmax = pll->vco_freq_max / ctl->den;
229 dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
230 fwant, fxtal, htotal, vtotal, fmax);
231 for (p = 1; p <= pll->post_shift_max; p++) {
232 if (fwant * 2 > fmax)
238 for (; p-- > 0; fwant >>= 1) {
241 if (fwant < fmin) break;
242 for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
247 n = (fwant * m) / fxtal;
248 if (n < pll->feed_div_min)
250 if (n > pll->feed_div_max)
265 dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
267 dprintk(KERN_DEBUG "Better...\n");
276 /* if h2/post/in/feed have not been assigned, return zero (error) */
280 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
281 return fxtal * (*feed) / (*in) * ctl->den;
284 static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
285 unsigned int htotal, unsigned int vtotal,
286 unsigned int* in, unsigned int* feed, unsigned int* post,
287 unsigned int* htotal2) {
289 unsigned int uninitialized_var(p);
291 fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
295 if (fvco <= 100000000)
297 else if (fvco <= 140000000)
299 else if (fvco <= 180000000)
307 static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
308 unsigned int* in, unsigned int* feed, unsigned int* post) {
312 fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
316 else if (fvco <= 140000)
318 else if (fvco <= 180000)
326 static unsigned char maven_compute_deflicker (const struct maven_data* md) {
329 df = (md->version == MGATVO_B?0x40:0x00);
330 switch (md->primary_head->altout.tvo_params.deflicker) {
344 static void maven_compute_bwlevel (const struct maven_data* md,
346 const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
347 const int c = md->primary_head->altout.tvo_params.contrast;
349 *bl = max(b - c, BLMIN);
350 *wl = min(b + c, WLMAX);
353 static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
354 return maven_gamma + md->primary_head->altout.tvo_params.gamma;
358 static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
359 static struct mavenregs palregs = { {
360 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
362 0x00, /* ? not written */
363 0x00, /* modified by code (F9 written...) */
364 0x00, /* ? not written */
370 0x00, /* ? not written */
371 0x3F, 0x03, /* 0E-0F */
372 0x3F, 0x03, /* 10-11 */
375 0x1C, 0x3D, 0x14, /* 14-16 */
376 0x9C, 0x01, /* 17-18 */
382 0x89, 0x03, /* 1E-1F */
393 0x55, 0x01, /* 2A-2B */
395 0x07, 0x7E, /* 2D-2E */
396 0x02, 0x54, /* 2F-30 */
397 0xB0, 0x00, /* 31-32 */
400 0x00, /* 35 written multiple times */
401 0x00, /* 36 not written */
407 0x3F, 0x03, /* 3C-3D */
408 0x00, /* 3E written multiple times */
409 0x00, /* 3F not written */
410 }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
411 static struct mavenregs ntscregs = { {
412 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
414 0x00, /* ? not written */
415 0x00, /* modified by code (F9 written...) */
416 0x00, /* ? not written */
422 0x00, /* ? not written */
423 0x41, 0x00, /* 0E-0F */
424 0x3C, 0x00, /* 10-11 */
427 0x1B, 0x1B, 0x24, /* 14-16 */
428 0x83, 0x01, /* 17-18 */
434 0x89, 0x02, /* 1E-1F */
445 0xFF, 0x03, /* 2A-2B */
447 0x0F, 0x78, /* 2D-2E */
448 0x00, 0x00, /* 2F-30 */
449 0xB2, 0x04, /* 31-32 */
452 0x00, /* 35 written multiple times */
453 0x00, /* 36 not written */
459 0x3C, 0x00, /* 3C-3D */
460 0x00, /* 3E written multiple times */
461 0x00, /* never written */
462 }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
463 MINFO_FROM(md->primary_head);
465 if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_PAL)
471 data->regs[0x93] = maven_compute_deflicker(md);
475 const struct maven_gamma* g;
476 g = maven_compute_gamma(md);
477 data->regs[0x83] = g->reg83;
478 data->regs[0x84] = g->reg84;
479 data->regs[0x85] = g->reg85;
480 data->regs[0x86] = g->reg86;
481 data->regs[0x87] = g->reg87;
482 data->regs[0x88] = g->reg88;
483 data->regs[0x89] = g->reg89;
484 data->regs[0x8A] = g->reg8a;
485 data->regs[0x8B] = g->reg8b;
488 /* Set contrast / brightness */
491 maven_compute_bwlevel (md, &bl, &wl);
492 data->regs[0x0e] = bl >> 2;
493 data->regs[0x0f] = bl & 3;
494 data->regs[0x1e] = wl >> 2;
495 data->regs[0x1f] = wl & 3;
501 data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
505 data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
509 #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
510 #define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
511 static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
515 maven_set_reg(c, 0x3E, 0x01);
516 maven_get_reg(c, 0x82); /* fetch oscillator state? */
517 maven_set_reg(c, 0x8C, 0x00);
518 maven_get_reg(c, 0x94); /* get 0x82 */
519 maven_set_reg(c, 0x94, 0xA2);
522 maven_set_reg_pair(c, 0x8E, 0x1EFF);
523 maven_set_reg(c, 0xC6, 0x01);
525 /* removed code... */
527 maven_get_reg(c, 0x06);
528 maven_set_reg(c, 0x06, 0xF9); /* or read |= 0xF0 ? */
530 /* removed code here... */
532 /* real code begins here? */
533 /* chroma subcarrier */
534 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
547 if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
548 maven_set_reg(c, 0x35, 0x10); /* ... */
550 maven_set_reg(c, 0x35, 0x0F); /* ... */
558 LR(0x20); /* saturation #1 */
559 LR(0x22); /* saturation #2 */
585 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
586 maven_set_reg(c, 0x35, 0x1D); /* ... */
588 maven_set_reg(c, 0x35, 0x1C);
593 maven_set_reg(c, 0xB3, 0x01);
595 maven_get_reg(c, 0xB0); /* read 0x80 */
596 maven_set_reg(c, 0xB0, 0x08); /* ugh... */
597 maven_get_reg(c, 0xB9); /* read 0x7C */
598 maven_set_reg(c, 0xB9, 0x78);
599 maven_get_reg(c, 0xBF); /* read 0x00 */
600 maven_set_reg(c, 0xBF, 0x02);
601 maven_get_reg(c, 0x94); /* read 0x82 */
602 maven_set_reg(c, 0x94, 0xB3);
604 LR(0x80); /* 04 1A 91 or 05 21 91 */
608 maven_set_reg(c, 0x8C, 0x20);
609 maven_get_reg(c, 0x8D);
610 maven_set_reg(c, 0x8D, 0x10);
612 LR(0x90); /* 4D 50 52 or 4E 05 45 */
616 LRP(0x9A); /* 0049 or 004F */
617 LRP(0x9C); /* 0004 or 0004 */
618 LRP(0x9E); /* 0458 or 045E */
619 LRP(0xA0); /* 05DA or 051B */
620 LRP(0xA2); /* 00CC or 00CF */
621 LRP(0xA4); /* 007D or 007F */
622 LRP(0xA6); /* 007C or 007E */
623 LRP(0xA8); /* 03CB or 03CE */
624 LRP(0x98); /* 0000 or 0000 */
625 LRP(0xAE); /* 0044 or 003A */
626 LRP(0x96); /* 05DA or 051B */
627 LRP(0xAA); /* 04BC or 046A */
628 LRP(0xAC); /* 004D or 004E */
633 maven_get_reg(c, 0x8D);
634 maven_set_reg(c, 0x8D, 0x04);
636 LR(0x20); /* saturation #1 */
637 LR(0x22); /* saturation #2 */
638 LR(0x93); /* whoops */
639 LR(0x20); /* oh, saturation #1 again */
640 LR(0x22); /* oh, saturation #2 again */
644 LRP(0x0E); /* problems with memory? */
645 LRP(0x1E); /* yes, matrox must have problems in memory area... */
647 /* load gamma correction stuff */
658 val = maven_get_reg(c, 0x8D);
659 val &= 0x14; /* 0x10 or anything ored with it */
660 maven_set_reg(c, 0x8D, val);
685 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
686 maven_set_reg(c, 0x35, 0x1D);
688 maven_set_reg(c, 0x35, 0x1C);
693 maven_get_reg(c, 0xB0);
694 LR(0xB0); /* output mode */
705 maven_set_reg(c, 0x3E, 0x00);
706 maven_set_reg(c, 0x95, 0x20);
709 static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
710 struct mavenregs* m) {
712 unsigned int err = ~0;
715 m->regs[0x80] = 0x0F;
716 m->regs[0x81] = 0x07;
717 m->regs[0x82] = 0x81;
719 for (x = 0; x < 8; x++) {
721 unsigned int uninitialized_var(a), uninitialized_var(b),
722 uninitialized_var(h2);
723 unsigned int h = ht + 2 + x;
725 if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
726 unsigned int diff = h - h2;
730 m->regs[0x80] = a - 1;
731 m->regs[0x81] = b - 1;
732 m->regs[0x82] = c | 0x80;
741 static inline int maven_compute_timming(struct maven_data* md,
742 struct my_timming* mt,
743 struct mavenregs* m) {
745 unsigned int a, bv, c;
746 MINFO_FROM(md->primary_head);
748 m->mode = ACCESS_FBINFO(outputs[1]).mode;
749 if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
750 unsigned int lmargin;
751 unsigned int umargin;
756 maven_init_TVdata(md, m);
758 if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
761 lmargin = mt->HTotal - mt->HSyncEnd;
762 slen = mt->HSyncEnd - mt->HSyncStart;
763 hcrt = mt->HTotal - slen - mt->delay;
764 umargin = mt->VTotal - mt->VSyncEnd;
765 vslen = mt->VSyncEnd - mt->VSyncStart;
767 if (m->hcorr < mt->HTotal)
769 if (hcrt > mt->HTotal)
771 if (hcrt + 2 > mt->HTotal)
772 hcrt = 0; /* or issue warning? */
774 /* last (first? middle?) line in picture can have different length */
776 m->regs[0x96] = m->hcorr;
777 m->regs[0x97] = m->hcorr >> 8;
779 m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
781 m->regs[0x9A] = lmargin; /* 100% */
782 m->regs[0x9B] = lmargin >> 8; /* 100% */
784 m->regs[0x9C] = 0x04;
785 m->regs[0x9D] = 0x00;
787 m->regs[0xA0] = m->htotal;
788 m->regs[0xA1] = m->htotal >> 8;
790 m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */
791 m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
792 /* something end... [A6]+1..[A8] */
793 if (md->version == MGATVO_B) {
794 m->regs[0xA4] = 0x04;
795 m->regs[0xA5] = 0x00;
797 m->regs[0xA4] = 0x01;
798 m->regs[0xA5] = 0x00;
800 /* something start... 0..[A4]-1 */
801 m->regs[0xA6] = 0x00;
802 m->regs[0xA7] = 0x00;
803 /* vertical line count - 1 */
804 m->regs[0xA8] = mt->VTotal - 1;
805 m->regs[0xA9] = (mt->VTotal - 1) >> 8;
806 /* horizontal vidrst pos */
807 m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */
808 m->regs[0xAB] = hcrt >> 8;
809 /* vertical vidrst pos */
810 m->regs[0xAC] = mt->VTotal - 2;
811 m->regs[0xAD] = (mt->VTotal - 2) >> 8;
812 /* moves picture up/down and so on... */
813 m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
814 m->regs[0xAF] = 0x00;
818 unsigned int ibmin = 4 + lmargin + mt->HDisplay;
823 /* Where 94208 came from? */
825 hdec = 94208 / (mt->HTotal);
833 hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
839 /* Now we have to compute input buffer length.
840 If you want any picture, it must be between
844 If you want perfect picture even on the top
845 of screen, it must be also
846 0x3C0000 * i / hdec + Q - R / hdec
856 ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
858 } while (ib < ibmin);
859 if (ib >= m->htotal + 2) {
863 m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
864 m->regs[0xC2] = hlen;
865 /* 'valid' input line length */
867 m->regs[0x9F] = ib >> 8;
873 #define MATROX_USE64BIT_DIVIDE
875 #ifdef MATROX_USE64BIT_DIVIDE
880 a = m->vlines * (m->htotal + 2);
881 b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
883 f1 = ((u64)a) << 15; /* *32768 */
887 vdec = m->vlines * 32768 / mt->VTotal;
893 vlen = (vslen + umargin + mt->VDisplay) * vdec;
894 vlen = (vlen >> 16) - 146; /* FIXME: 146?! */
900 m->regs[0x91] = vdec;
901 m->regs[0x92] = vdec >> 8;
902 m->regs[0xBE] = vlen;
904 m->regs[0xB0] = 0x08; /* output: SVideo/Composite */
908 DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
911 m->regs[0x82] = c | 0x80;
913 m->regs[0xB3] = 0x01;
914 m->regs[0x94] = 0xB2;
917 m->regs[0x96] = mt->HTotal;
918 m->regs[0x97] = mt->HTotal >> 8;
920 m->regs[0x98] = 0x00;
921 m->regs[0x99] = 0x00;
923 tmpi = mt->HSyncEnd - mt->HSyncStart;
924 m->regs[0x9A] = tmpi;
925 m->regs[0x9B] = tmpi >> 8;
927 tmpi = mt->HTotal - mt->HSyncStart;
928 m->regs[0x9C] = tmpi;
929 m->regs[0x9D] = tmpi >> 8;
931 tmpi += mt->HDisplay;
932 m->regs[0x9E] = tmpi;
933 m->regs[0x9F] = tmpi >> 8;
935 tmpi = mt->HTotal + 1;
936 m->regs[0xA0] = tmpi;
937 m->regs[0xA1] = tmpi >> 8;
939 tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
940 m->regs[0xA2] = tmpi;
941 m->regs[0xA3] = tmpi >> 8;
943 tmpi = mt->VTotal - mt->VSyncStart;
944 m->regs[0xA4] = tmpi;
945 m->regs[0xA5] = tmpi >> 8;
947 tmpi = mt->VTotal - 1;
948 m->regs[0xA6] = tmpi;
949 m->regs[0xA7] = tmpi >> 8;
951 m->regs[0xA8] = tmpi;
952 m->regs[0xA9] = tmpi >> 8;
954 tmpi = mt->HTotal - mt->delay;
955 m->regs[0xAA] = tmpi;
956 m->regs[0xAB] = tmpi >> 8;
958 tmpi = mt->VTotal - 2;
959 m->regs[0xAC] = tmpi;
960 m->regs[0xAD] = tmpi >> 8;
962 m->regs[0xAE] = 0x00;
963 m->regs[0xAF] = 0x00;
965 m->regs[0xB0] = 0x03; /* output: monitor */
966 m->regs[0xB1] = 0xA0; /* ??? */
967 m->regs[0x8C] = 0x20; /* must be set... */
968 m->regs[0x8D] = 0x04; /* defaults to 0x10: test signal */
969 m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
970 m->regs[0xBF] = 0x22; /* makes picture stable */
975 static int maven_program_timming(struct maven_data* md,
976 const struct mavenregs* m) {
977 struct i2c_client* c = &md->client;
979 if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
1001 LR(0xB0); /* output: monitor */
1003 LR(0x8C); /* must be set... */
1004 LR(0x8D); /* defaults to 0x10: test signal */
1005 LR(0xB9); /* defaults to 0x2C: too bright */
1006 LR(0xBF); /* makes picture stable */
1008 maven_init_TV(c, m);
1013 static inline int maven_resync(struct maven_data* md) {
1014 struct i2c_client* c = &md->client;
1015 maven_set_reg(c, 0x95, 0x20); /* start whole thing */
1019 static int maven_get_queryctrl (struct maven_data* md,
1020 struct v4l2_queryctrl *p) {
1023 i = get_ctrl_id(p->id);
1025 *p = maven_controls[i].desc;
1029 static const struct v4l2_queryctrl disctrl =
1030 { .flags = V4L2_CTRL_FLAG_DISABLED };
1035 sprintf(p->name, "Ctrl #%08X", i);
1041 static int maven_set_control (struct maven_data* md,
1042 struct v4l2_control *p) {
1045 i = get_ctrl_id(p->id);
1046 if (i < 0) return -EINVAL;
1051 if (p->value == *get_ctrl_ptr(md, i)) return 0;
1056 if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
1057 if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
1062 *get_ctrl_ptr(md, i) = p->value;
1065 case V4L2_CID_BRIGHTNESS:
1066 case V4L2_CID_CONTRAST:
1068 int blacklevel, whitelevel;
1069 maven_compute_bwlevel(md, &blacklevel, &whitelevel);
1070 blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
1071 whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
1072 maven_set_reg_pair(&md->client, 0x0e, blacklevel);
1073 maven_set_reg_pair(&md->client, 0x1e, whitelevel);
1076 case V4L2_CID_SATURATION:
1078 maven_set_reg(&md->client, 0x20, p->value);
1079 maven_set_reg(&md->client, 0x22, p->value);
1084 maven_set_reg(&md->client, 0x25, p->value);
1087 case V4L2_CID_GAMMA:
1089 const struct maven_gamma* g;
1090 g = maven_compute_gamma(md);
1091 maven_set_reg(&md->client, 0x83, g->reg83);
1092 maven_set_reg(&md->client, 0x84, g->reg84);
1093 maven_set_reg(&md->client, 0x85, g->reg85);
1094 maven_set_reg(&md->client, 0x86, g->reg86);
1095 maven_set_reg(&md->client, 0x87, g->reg87);
1096 maven_set_reg(&md->client, 0x88, g->reg88);
1097 maven_set_reg(&md->client, 0x89, g->reg89);
1098 maven_set_reg(&md->client, 0x8a, g->reg8a);
1099 maven_set_reg(&md->client, 0x8b, g->reg8b);
1102 case MATROXFB_CID_TESTOUT:
1105 = maven_get_reg(&md->client,0x8d);
1106 if (p->value) val |= 0x10;
1108 maven_set_reg(&md->client, 0x8d, val);
1111 case MATROXFB_CID_DEFLICKER:
1113 maven_set_reg(&md->client, 0x93, maven_compute_deflicker(md));
1122 static int maven_get_control (struct maven_data* md,
1123 struct v4l2_control *p) {
1126 i = get_ctrl_id(p->id);
1127 if (i < 0) return -EINVAL;
1128 p->value = *get_ctrl_ptr(md, i);
1132 /******************************************************/
1134 static int maven_out_compute(void* md, struct my_timming* mt) {
1135 #define mdinfo ((struct maven_data*)md)
1136 #define minfo (mdinfo->primary_head)
1137 return maven_compute_timming(md, mt, &ACCESS_FBINFO(hw).maven);
1142 static int maven_out_program(void* md) {
1143 #define mdinfo ((struct maven_data*)md)
1144 #define minfo (mdinfo->primary_head)
1145 return maven_program_timming(md, &ACCESS_FBINFO(hw).maven);
1150 static int maven_out_start(void* md) {
1151 return maven_resync(md);
1154 static int maven_out_verify_mode(void* md, u_int32_t arg) {
1156 case MATROXFB_OUTPUT_MODE_PAL:
1157 case MATROXFB_OUTPUT_MODE_NTSC:
1158 case MATROXFB_OUTPUT_MODE_MONITOR:
1164 static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) {
1165 return maven_get_queryctrl(md, p);
1168 static int maven_out_get_ctrl(void* md, struct v4l2_control* p) {
1169 return maven_get_control(md, p);
1172 static int maven_out_set_ctrl(void* md, struct v4l2_control* p) {
1173 return maven_set_control(md, p);
1176 static struct matrox_altout maven_altout = {
1177 .name = "Secondary output",
1178 .compute = maven_out_compute,
1179 .program = maven_out_program,
1180 .start = maven_out_start,
1181 .verifymode = maven_out_verify_mode,
1182 .getqueryctrl = maven_out_get_queryctrl,
1183 .getctrl = maven_out_get_ctrl,
1184 .setctrl = maven_out_set_ctrl,
1187 static int maven_init_client(struct i2c_client* clnt) {
1188 struct maven_data* md = i2c_get_clientdata(clnt);
1189 MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo);
1191 md->primary_head = MINFO;
1192 down_write(&ACCESS_FBINFO(altout.lock));
1193 ACCESS_FBINFO(outputs[1]).output = &maven_altout;
1194 ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
1195 ACCESS_FBINFO(outputs[1]).data = md;
1196 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1197 up_write(&ACCESS_FBINFO(altout.lock));
1198 if (maven_get_reg(clnt, 0xB2) < 0x14) {
1199 md->version = MGATVO_B;
1200 /* Tweak some things for this old chip */
1202 md->version = MGATVO_C;
1205 * Set all parameters to its initial values.
1210 for (i = 0; i < MAVCTRLS; ++i) {
1211 *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
1218 static int maven_shutdown_client(struct i2c_client* clnt) {
1219 struct maven_data* md = i2c_get_clientdata(clnt);
1221 if (md->primary_head) {
1222 MINFO_FROM(md->primary_head);
1224 down_write(&ACCESS_FBINFO(altout.lock));
1225 ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
1226 ACCESS_FBINFO(outputs[1]).output = NULL;
1227 ACCESS_FBINFO(outputs[1]).data = NULL;
1228 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1229 up_write(&ACCESS_FBINFO(altout.lock));
1230 md->primary_head = NULL;
1235 static const unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
1238 static struct i2c_driver maven_driver;
1240 static int maven_detect_client(struct i2c_adapter* adapter, int address, int kind) {
1242 struct i2c_client* new_client;
1243 struct maven_data* data;
1245 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
1246 I2C_FUNC_SMBUS_BYTE_DATA |
1247 I2C_FUNC_PROTOCOL_MANGLING))
1249 if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
1253 new_client = &data->client;
1254 i2c_set_clientdata(new_client, data);
1255 new_client->addr = address;
1256 new_client->adapter = adapter;
1257 new_client->driver = &maven_driver;
1258 new_client->flags = 0;
1259 strlcpy(new_client->name, "maven", I2C_NAME_SIZE);
1260 if ((err = i2c_attach_client(new_client)))
1262 err = maven_init_client(new_client);
1267 i2c_detach_client(new_client);
1274 static int maven_attach_adapter(struct i2c_adapter* adapter) {
1275 if (adapter->id == I2C_HW_B_G400)
1276 return i2c_probe(adapter, &addr_data, &maven_detect_client);
1280 static int maven_detach_client(struct i2c_client* client) {
1283 if ((err = i2c_detach_client(client)))
1285 maven_shutdown_client(client);
1286 kfree(i2c_get_clientdata(client));
1290 static struct i2c_driver maven_driver={
1294 .id = I2C_DRIVERID_MGATVO,
1295 .attach_adapter = maven_attach_adapter,
1296 .detach_client = maven_detach_client,
1299 static int __init matroxfb_maven_init(void)
1301 return i2c_add_driver(&maven_driver);
1304 static void __exit matroxfb_maven_exit(void)
1306 i2c_del_driver(&maven_driver);
1309 MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1310 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1311 MODULE_LICENSE("GPL");
1312 module_init(matroxfb_maven_init);
1313 module_exit(matroxfb_maven_exit);
1314 /* we do not have __setup() yet */