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>
21 #include <asm/uaccess.h>
23 #define MAVEN_I2CID (0x1B)
28 static const struct maven_gamma {
39 { 131, 57, 223, 15, 117, 212, 251, 91, 156},
40 { 133, 61, 128, 63, 180, 147, 195, 100, 180},
41 { 131, 19, 63, 31, 50, 66, 171, 64, 176},
42 { 0, 0, 0, 31, 16, 16, 16, 100, 200},
43 { 8, 23, 47, 73, 147, 244, 220, 80, 195},
44 { 22, 43, 64, 80, 147, 115, 58, 85, 168},
45 { 34, 60, 80, 214, 147, 212, 188, 85, 167},
46 { 45, 77, 96, 216, 147, 99, 91, 85, 159},
47 { 56, 76, 112, 107, 147, 212, 148, 64, 144},
48 { 65, 91, 128, 137, 147, 196, 17, 69, 148},
49 { 72, 104, 136, 138, 147, 180, 245, 73, 147},
50 { 87, 116, 143, 126, 16, 83, 229, 77, 144},
51 { 95, 119, 152, 254, 244, 83, 221, 77, 151},
52 { 100, 129, 159, 156, 244, 148, 197, 77, 160},
53 { 105, 141, 167, 247, 244, 132, 181, 84, 166},
54 { 105, 147, 168, 247, 244, 245, 181, 90, 170},
55 { 120, 153, 175, 248, 212, 229, 165, 90, 180},
56 { 119, 156, 176, 248, 244, 229, 84, 74, 160},
57 { 119, 158, 183, 248, 244, 229, 149, 78, 165}
60 /* Definition of the various controls */
62 struct v4l2_queryctrl desc;
69 static const struct mctl maven_controls[] =
70 { { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
72 0, WLMAX - BLMIN, 1, 379 - BLMIN,
74 }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
75 { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
79 }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
80 { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
84 }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
85 { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
89 }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
90 { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER,
92 0, ARRAY_SIZE(maven_gamma) - 1, 1, 3,
94 }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
95 { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
99 }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
100 { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER,
104 }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
108 #define MAVCTRLS ARRAY_SIZE(maven_controls)
110 /* Return: positive number: id found
111 -EINVAL: id not found, return failure
112 -ENOENT: id not found, create fake disabled control */
113 static int get_ctrl_id(__u32 v4l2_id) {
116 for (i = 0; i < MAVCTRLS; i++) {
117 if (v4l2_id < maven_controls[i].desc.id) {
118 if (maven_controls[i].desc.id == 0x08000000) {
123 if (v4l2_id == maven_controls[i].desc.id) {
131 struct matrox_fb_info* primary_head;
132 struct i2c_client client;
136 static int* get_ctrl_ptr(struct maven_data* md, int idx) {
137 return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
140 static int maven_get_reg(struct i2c_client* c, char reg) {
142 struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® },
143 { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }};
146 err = i2c_transfer(c->adapter, msgs, 2);
148 printk(KERN_INFO "ReadReg(%d) failed\n", reg);
152 static int maven_set_reg(struct i2c_client* c, int reg, int val) {
155 err = i2c_smbus_write_byte_data(c, reg, val);
157 printk(KERN_INFO "WriteReg(%d) failed\n", reg);
161 static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
164 err = i2c_smbus_write_word_data(c, reg, val);
166 printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
170 static const struct matrox_pll_features maven_pll = {
178 struct matrox_pll_features2 {
179 unsigned int vco_freq_min;
180 unsigned int vco_freq_max;
181 unsigned int feed_div_min;
182 unsigned int feed_div_max;
183 unsigned int in_div_min;
184 unsigned int in_div_max;
185 unsigned int post_shift_max;
188 struct matrox_pll_ctl {
189 unsigned int ref_freq;
193 static const struct matrox_pll_features2 maven1000_pll = {
201 static const struct matrox_pll_ctl maven_PAL = {
206 static const struct matrox_pll_ctl maven_NTSC = {
207 450450, /* 27027000/60 == 27000000/59.94005994 */
211 static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
212 const struct matrox_pll_ctl* ctl,
213 unsigned int htotal, unsigned int vtotal,
214 unsigned int* in, unsigned int* feed, unsigned int* post,
216 unsigned int besth2 = 0;
217 unsigned int fxtal = ctl->ref_freq;
218 unsigned int fmin = pll->vco_freq_min / ctl->den;
226 scrlen = htotal * (vtotal - 1);
227 fwant = htotal * vtotal;
228 fmax = pll->vco_freq_max / ctl->den;
230 dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
231 fwant, fxtal, htotal, vtotal, fmax);
232 for (p = 1; p <= pll->post_shift_max; p++) {
233 if (fwant * 2 > fmax)
239 for (; p-- > 0; fwant >>= 1) {
242 if (fwant < fmin) break;
243 for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
248 n = (fwant * m) / fxtal;
249 if (n < pll->feed_div_min)
251 if (n > pll->feed_div_max)
266 dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
268 dprintk(KERN_DEBUG "Better...\n");
277 /* if h2/post/in/feed have not been assigned, return zero (error) */
281 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
282 return fxtal * (*feed) / (*in) * ctl->den;
285 static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
286 unsigned int htotal, unsigned int vtotal,
287 unsigned int* in, unsigned int* feed, unsigned int* post,
288 unsigned int* htotal2) {
290 unsigned int uninitialized_var(p);
292 fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
296 if (fvco <= 100000000)
298 else if (fvco <= 140000000)
300 else if (fvco <= 180000000)
308 static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
309 unsigned int* in, unsigned int* feed, unsigned int* post) {
313 fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
317 else if (fvco <= 140000)
319 else if (fvco <= 180000)
327 static unsigned char maven_compute_deflicker (const struct maven_data* md) {
330 df = (md->version == MGATVO_B?0x40:0x00);
331 switch (md->primary_head->altout.tvo_params.deflicker) {
345 static void maven_compute_bwlevel (const struct maven_data* md,
347 const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
348 const int c = md->primary_head->altout.tvo_params.contrast;
350 *bl = max(b - c, BLMIN);
351 *wl = min(b + c, WLMAX);
354 static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
355 return maven_gamma + md->primary_head->altout.tvo_params.gamma;
359 static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
360 static struct mavenregs palregs = { {
361 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
363 0x00, /* ? not written */
364 0x00, /* modified by code (F9 written...) */
365 0x00, /* ? not written */
371 0x00, /* ? not written */
372 0x3F, 0x03, /* 0E-0F */
373 0x3F, 0x03, /* 10-11 */
376 0x1C, 0x3D, 0x14, /* 14-16 */
377 0x9C, 0x01, /* 17-18 */
383 0x89, 0x03, /* 1E-1F */
394 0x55, 0x01, /* 2A-2B */
396 0x07, 0x7E, /* 2D-2E */
397 0x02, 0x54, /* 2F-30 */
398 0xB0, 0x00, /* 31-32 */
401 0x00, /* 35 written multiple times */
402 0x00, /* 36 not written */
408 0x3F, 0x03, /* 3C-3D */
409 0x00, /* 3E written multiple times */
410 0x00, /* 3F not written */
411 }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
412 static struct mavenregs ntscregs = { {
413 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
415 0x00, /* ? not written */
416 0x00, /* modified by code (F9 written...) */
417 0x00, /* ? not written */
423 0x00, /* ? not written */
424 0x41, 0x00, /* 0E-0F */
425 0x3C, 0x00, /* 10-11 */
428 0x1B, 0x1B, 0x24, /* 14-16 */
429 0x83, 0x01, /* 17-18 */
435 0x89, 0x02, /* 1E-1F */
446 0xFF, 0x03, /* 2A-2B */
448 0x0F, 0x78, /* 2D-2E */
449 0x00, 0x00, /* 2F-30 */
450 0xB2, 0x04, /* 31-32 */
453 0x00, /* 35 written multiple times */
454 0x00, /* 36 not written */
460 0x3C, 0x00, /* 3C-3D */
461 0x00, /* 3E written multiple times */
462 0x00, /* never written */
463 }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
464 MINFO_FROM(md->primary_head);
466 if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_PAL)
472 data->regs[0x93] = maven_compute_deflicker(md);
476 const struct maven_gamma* g;
477 g = maven_compute_gamma(md);
478 data->regs[0x83] = g->reg83;
479 data->regs[0x84] = g->reg84;
480 data->regs[0x85] = g->reg85;
481 data->regs[0x86] = g->reg86;
482 data->regs[0x87] = g->reg87;
483 data->regs[0x88] = g->reg88;
484 data->regs[0x89] = g->reg89;
485 data->regs[0x8A] = g->reg8a;
486 data->regs[0x8B] = g->reg8b;
489 /* Set contrast / brightness */
492 maven_compute_bwlevel (md, &bl, &wl);
493 data->regs[0x0e] = bl >> 2;
494 data->regs[0x0f] = bl & 3;
495 data->regs[0x1e] = wl >> 2;
496 data->regs[0x1f] = wl & 3;
502 data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
506 data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
510 #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
511 #define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
512 static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
516 maven_set_reg(c, 0x3E, 0x01);
517 maven_get_reg(c, 0x82); /* fetch oscillator state? */
518 maven_set_reg(c, 0x8C, 0x00);
519 maven_get_reg(c, 0x94); /* get 0x82 */
520 maven_set_reg(c, 0x94, 0xA2);
523 maven_set_reg_pair(c, 0x8E, 0x1EFF);
524 maven_set_reg(c, 0xC6, 0x01);
526 /* removed code... */
528 maven_get_reg(c, 0x06);
529 maven_set_reg(c, 0x06, 0xF9); /* or read |= 0xF0 ? */
531 /* removed code here... */
533 /* real code begins here? */
534 /* chroma subcarrier */
535 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
548 if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
549 maven_set_reg(c, 0x35, 0x10); /* ... */
551 maven_set_reg(c, 0x35, 0x0F); /* ... */
559 LR(0x20); /* saturation #1 */
560 LR(0x22); /* saturation #2 */
586 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
587 maven_set_reg(c, 0x35, 0x1D); /* ... */
589 maven_set_reg(c, 0x35, 0x1C);
594 maven_set_reg(c, 0xB3, 0x01);
596 maven_get_reg(c, 0xB0); /* read 0x80 */
597 maven_set_reg(c, 0xB0, 0x08); /* ugh... */
598 maven_get_reg(c, 0xB9); /* read 0x7C */
599 maven_set_reg(c, 0xB9, 0x78);
600 maven_get_reg(c, 0xBF); /* read 0x00 */
601 maven_set_reg(c, 0xBF, 0x02);
602 maven_get_reg(c, 0x94); /* read 0x82 */
603 maven_set_reg(c, 0x94, 0xB3);
605 LR(0x80); /* 04 1A 91 or 05 21 91 */
609 maven_set_reg(c, 0x8C, 0x20);
610 maven_get_reg(c, 0x8D);
611 maven_set_reg(c, 0x8D, 0x10);
613 LR(0x90); /* 4D 50 52 or 4E 05 45 */
617 LRP(0x9A); /* 0049 or 004F */
618 LRP(0x9C); /* 0004 or 0004 */
619 LRP(0x9E); /* 0458 or 045E */
620 LRP(0xA0); /* 05DA or 051B */
621 LRP(0xA2); /* 00CC or 00CF */
622 LRP(0xA4); /* 007D or 007F */
623 LRP(0xA6); /* 007C or 007E */
624 LRP(0xA8); /* 03CB or 03CE */
625 LRP(0x98); /* 0000 or 0000 */
626 LRP(0xAE); /* 0044 or 003A */
627 LRP(0x96); /* 05DA or 051B */
628 LRP(0xAA); /* 04BC or 046A */
629 LRP(0xAC); /* 004D or 004E */
634 maven_get_reg(c, 0x8D);
635 maven_set_reg(c, 0x8D, 0x04);
637 LR(0x20); /* saturation #1 */
638 LR(0x22); /* saturation #2 */
639 LR(0x93); /* whoops */
640 LR(0x20); /* oh, saturation #1 again */
641 LR(0x22); /* oh, saturation #2 again */
645 LRP(0x0E); /* problems with memory? */
646 LRP(0x1E); /* yes, matrox must have problems in memory area... */
648 /* load gamma correction stuff */
659 val = maven_get_reg(c, 0x8D);
660 val &= 0x14; /* 0x10 or anything ored with it */
661 maven_set_reg(c, 0x8D, val);
686 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
687 maven_set_reg(c, 0x35, 0x1D);
689 maven_set_reg(c, 0x35, 0x1C);
694 maven_get_reg(c, 0xB0);
695 LR(0xB0); /* output mode */
706 maven_set_reg(c, 0x3E, 0x00);
707 maven_set_reg(c, 0x95, 0x20);
710 static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
711 struct mavenregs* m) {
713 unsigned int err = ~0;
716 m->regs[0x80] = 0x0F;
717 m->regs[0x81] = 0x07;
718 m->regs[0x82] = 0x81;
720 for (x = 0; x < 8; x++) {
722 unsigned int uninitialized_var(a), uninitialized_var(b),
723 uninitialized_var(h2);
724 unsigned int h = ht + 2 + x;
726 if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
727 unsigned int diff = h - h2;
731 m->regs[0x80] = a - 1;
732 m->regs[0x81] = b - 1;
733 m->regs[0x82] = c | 0x80;
742 static inline int maven_compute_timming(struct maven_data* md,
743 struct my_timming* mt,
744 struct mavenregs* m) {
746 unsigned int a, bv, c;
747 MINFO_FROM(md->primary_head);
749 m->mode = ACCESS_FBINFO(outputs[1]).mode;
750 if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
751 unsigned int lmargin;
752 unsigned int umargin;
757 maven_init_TVdata(md, m);
759 if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
762 lmargin = mt->HTotal - mt->HSyncEnd;
763 slen = mt->HSyncEnd - mt->HSyncStart;
764 hcrt = mt->HTotal - slen - mt->delay;
765 umargin = mt->VTotal - mt->VSyncEnd;
766 vslen = mt->VSyncEnd - mt->VSyncStart;
768 if (m->hcorr < mt->HTotal)
770 if (hcrt > mt->HTotal)
772 if (hcrt + 2 > mt->HTotal)
773 hcrt = 0; /* or issue warning? */
775 /* last (first? middle?) line in picture can have different length */
777 m->regs[0x96] = m->hcorr;
778 m->regs[0x97] = m->hcorr >> 8;
780 m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
782 m->regs[0x9A] = lmargin; /* 100% */
783 m->regs[0x9B] = lmargin >> 8; /* 100% */
785 m->regs[0x9C] = 0x04;
786 m->regs[0x9D] = 0x00;
788 m->regs[0xA0] = m->htotal;
789 m->regs[0xA1] = m->htotal >> 8;
791 m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */
792 m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
793 /* something end... [A6]+1..[A8] */
794 if (md->version == MGATVO_B) {
795 m->regs[0xA4] = 0x04;
796 m->regs[0xA5] = 0x00;
798 m->regs[0xA4] = 0x01;
799 m->regs[0xA5] = 0x00;
801 /* something start... 0..[A4]-1 */
802 m->regs[0xA6] = 0x00;
803 m->regs[0xA7] = 0x00;
804 /* vertical line count - 1 */
805 m->regs[0xA8] = mt->VTotal - 1;
806 m->regs[0xA9] = (mt->VTotal - 1) >> 8;
807 /* horizontal vidrst pos */
808 m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */
809 m->regs[0xAB] = hcrt >> 8;
810 /* vertical vidrst pos */
811 m->regs[0xAC] = mt->VTotal - 2;
812 m->regs[0xAD] = (mt->VTotal - 2) >> 8;
813 /* moves picture up/down and so on... */
814 m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
815 m->regs[0xAF] = 0x00;
819 unsigned int ibmin = 4 + lmargin + mt->HDisplay;
824 /* Where 94208 came from? */
826 hdec = 94208 / (mt->HTotal);
834 hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
840 /* Now we have to compute input buffer length.
841 If you want any picture, it must be between
845 If you want perfect picture even on the top
846 of screen, it must be also
847 0x3C0000 * i / hdec + Q - R / hdec
857 ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
859 } while (ib < ibmin);
860 if (ib >= m->htotal + 2) {
864 m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
865 m->regs[0xC2] = hlen;
866 /* 'valid' input line length */
868 m->regs[0x9F] = ib >> 8;
874 #define MATROX_USE64BIT_DIVIDE
876 #ifdef MATROX_USE64BIT_DIVIDE
881 a = m->vlines * (m->htotal + 2);
882 b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
884 f1 = ((u64)a) << 15; /* *32768 */
888 vdec = m->vlines * 32768 / mt->VTotal;
894 vlen = (vslen + umargin + mt->VDisplay) * vdec;
895 vlen = (vlen >> 16) - 146; /* FIXME: 146?! */
901 m->regs[0x91] = vdec;
902 m->regs[0x92] = vdec >> 8;
903 m->regs[0xBE] = vlen;
905 m->regs[0xB0] = 0x08; /* output: SVideo/Composite */
909 DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
912 m->regs[0x82] = c | 0x80;
914 m->regs[0xB3] = 0x01;
915 m->regs[0x94] = 0xB2;
918 m->regs[0x96] = mt->HTotal;
919 m->regs[0x97] = mt->HTotal >> 8;
921 m->regs[0x98] = 0x00;
922 m->regs[0x99] = 0x00;
924 tmpi = mt->HSyncEnd - mt->HSyncStart;
925 m->regs[0x9A] = tmpi;
926 m->regs[0x9B] = tmpi >> 8;
928 tmpi = mt->HTotal - mt->HSyncStart;
929 m->regs[0x9C] = tmpi;
930 m->regs[0x9D] = tmpi >> 8;
932 tmpi += mt->HDisplay;
933 m->regs[0x9E] = tmpi;
934 m->regs[0x9F] = tmpi >> 8;
936 tmpi = mt->HTotal + 1;
937 m->regs[0xA0] = tmpi;
938 m->regs[0xA1] = tmpi >> 8;
940 tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
941 m->regs[0xA2] = tmpi;
942 m->regs[0xA3] = tmpi >> 8;
944 tmpi = mt->VTotal - mt->VSyncStart;
945 m->regs[0xA4] = tmpi;
946 m->regs[0xA5] = tmpi >> 8;
948 tmpi = mt->VTotal - 1;
949 m->regs[0xA6] = tmpi;
950 m->regs[0xA7] = tmpi >> 8;
952 m->regs[0xA8] = tmpi;
953 m->regs[0xA9] = tmpi >> 8;
955 tmpi = mt->HTotal - mt->delay;
956 m->regs[0xAA] = tmpi;
957 m->regs[0xAB] = tmpi >> 8;
959 tmpi = mt->VTotal - 2;
960 m->regs[0xAC] = tmpi;
961 m->regs[0xAD] = tmpi >> 8;
963 m->regs[0xAE] = 0x00;
964 m->regs[0xAF] = 0x00;
966 m->regs[0xB0] = 0x03; /* output: monitor */
967 m->regs[0xB1] = 0xA0; /* ??? */
968 m->regs[0x8C] = 0x20; /* must be set... */
969 m->regs[0x8D] = 0x04; /* defaults to 0x10: test signal */
970 m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
971 m->regs[0xBF] = 0x22; /* makes picture stable */
976 static int maven_program_timming(struct maven_data* md,
977 const struct mavenregs* m) {
978 struct i2c_client* c = &md->client;
980 if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
1002 LR(0xB0); /* output: monitor */
1004 LR(0x8C); /* must be set... */
1005 LR(0x8D); /* defaults to 0x10: test signal */
1006 LR(0xB9); /* defaults to 0x2C: too bright */
1007 LR(0xBF); /* makes picture stable */
1009 maven_init_TV(c, m);
1014 static inline int maven_resync(struct maven_data* md) {
1015 struct i2c_client* c = &md->client;
1016 maven_set_reg(c, 0x95, 0x20); /* start whole thing */
1020 static int maven_get_queryctrl (struct maven_data* md,
1021 struct v4l2_queryctrl *p) {
1024 i = get_ctrl_id(p->id);
1026 *p = maven_controls[i].desc;
1030 static const struct v4l2_queryctrl disctrl =
1031 { .flags = V4L2_CTRL_FLAG_DISABLED };
1036 sprintf(p->name, "Ctrl #%08X", i);
1042 static int maven_set_control (struct maven_data* md,
1043 struct v4l2_control *p) {
1046 i = get_ctrl_id(p->id);
1047 if (i < 0) return -EINVAL;
1052 if (p->value == *get_ctrl_ptr(md, i)) return 0;
1057 if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
1058 if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
1063 *get_ctrl_ptr(md, i) = p->value;
1066 case V4L2_CID_BRIGHTNESS:
1067 case V4L2_CID_CONTRAST:
1069 int blacklevel, whitelevel;
1070 maven_compute_bwlevel(md, &blacklevel, &whitelevel);
1071 blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
1072 whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
1073 maven_set_reg_pair(&md->client, 0x0e, blacklevel);
1074 maven_set_reg_pair(&md->client, 0x1e, whitelevel);
1077 case V4L2_CID_SATURATION:
1079 maven_set_reg(&md->client, 0x20, p->value);
1080 maven_set_reg(&md->client, 0x22, p->value);
1085 maven_set_reg(&md->client, 0x25, p->value);
1088 case V4L2_CID_GAMMA:
1090 const struct maven_gamma* g;
1091 g = maven_compute_gamma(md);
1092 maven_set_reg(&md->client, 0x83, g->reg83);
1093 maven_set_reg(&md->client, 0x84, g->reg84);
1094 maven_set_reg(&md->client, 0x85, g->reg85);
1095 maven_set_reg(&md->client, 0x86, g->reg86);
1096 maven_set_reg(&md->client, 0x87, g->reg87);
1097 maven_set_reg(&md->client, 0x88, g->reg88);
1098 maven_set_reg(&md->client, 0x89, g->reg89);
1099 maven_set_reg(&md->client, 0x8a, g->reg8a);
1100 maven_set_reg(&md->client, 0x8b, g->reg8b);
1103 case MATROXFB_CID_TESTOUT:
1106 = maven_get_reg(&md->client,0x8d);
1107 if (p->value) val |= 0x10;
1109 maven_set_reg(&md->client, 0x8d, val);
1112 case MATROXFB_CID_DEFLICKER:
1114 maven_set_reg(&md->client, 0x93, maven_compute_deflicker(md));
1123 static int maven_get_control (struct maven_data* md,
1124 struct v4l2_control *p) {
1127 i = get_ctrl_id(p->id);
1128 if (i < 0) return -EINVAL;
1129 p->value = *get_ctrl_ptr(md, i);
1133 /******************************************************/
1135 static int maven_out_compute(void* md, struct my_timming* mt) {
1136 #define mdinfo ((struct maven_data*)md)
1137 #define minfo (mdinfo->primary_head)
1138 return maven_compute_timming(md, mt, &ACCESS_FBINFO(hw).maven);
1143 static int maven_out_program(void* md) {
1144 #define mdinfo ((struct maven_data*)md)
1145 #define minfo (mdinfo->primary_head)
1146 return maven_program_timming(md, &ACCESS_FBINFO(hw).maven);
1151 static int maven_out_start(void* md) {
1152 return maven_resync(md);
1155 static int maven_out_verify_mode(void* md, u_int32_t arg) {
1157 case MATROXFB_OUTPUT_MODE_PAL:
1158 case MATROXFB_OUTPUT_MODE_NTSC:
1159 case MATROXFB_OUTPUT_MODE_MONITOR:
1165 static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) {
1166 return maven_get_queryctrl(md, p);
1169 static int maven_out_get_ctrl(void* md, struct v4l2_control* p) {
1170 return maven_get_control(md, p);
1173 static int maven_out_set_ctrl(void* md, struct v4l2_control* p) {
1174 return maven_set_control(md, p);
1177 static struct matrox_altout maven_altout = {
1178 .name = "Secondary output",
1179 .compute = maven_out_compute,
1180 .program = maven_out_program,
1181 .start = maven_out_start,
1182 .verifymode = maven_out_verify_mode,
1183 .getqueryctrl = maven_out_get_queryctrl,
1184 .getctrl = maven_out_get_ctrl,
1185 .setctrl = maven_out_set_ctrl,
1188 static int maven_init_client(struct i2c_client* clnt) {
1189 struct maven_data* md = i2c_get_clientdata(clnt);
1190 MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo);
1192 md->primary_head = MINFO;
1193 down_write(&ACCESS_FBINFO(altout.lock));
1194 ACCESS_FBINFO(outputs[1]).output = &maven_altout;
1195 ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
1196 ACCESS_FBINFO(outputs[1]).data = md;
1197 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1198 up_write(&ACCESS_FBINFO(altout.lock));
1199 if (maven_get_reg(clnt, 0xB2) < 0x14) {
1200 md->version = MGATVO_B;
1201 /* Tweak some things for this old chip */
1203 md->version = MGATVO_C;
1206 * Set all parameters to its initial values.
1211 for (i = 0; i < MAVCTRLS; ++i) {
1212 *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
1219 static int maven_shutdown_client(struct i2c_client* clnt) {
1220 struct maven_data* md = i2c_get_clientdata(clnt);
1222 if (md->primary_head) {
1223 MINFO_FROM(md->primary_head);
1225 down_write(&ACCESS_FBINFO(altout.lock));
1226 ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
1227 ACCESS_FBINFO(outputs[1]).output = NULL;
1228 ACCESS_FBINFO(outputs[1]).data = NULL;
1229 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1230 up_write(&ACCESS_FBINFO(altout.lock));
1231 md->primary_head = NULL;
1236 static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
1239 static struct i2c_driver maven_driver;
1241 static int maven_detect_client(struct i2c_adapter* adapter, int address, int kind) {
1243 struct i2c_client* new_client;
1244 struct maven_data* data;
1246 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
1247 I2C_FUNC_SMBUS_BYTE_DATA |
1248 I2C_FUNC_PROTOCOL_MANGLING))
1250 if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
1254 new_client = &data->client;
1255 i2c_set_clientdata(new_client, data);
1256 new_client->addr = address;
1257 new_client->adapter = adapter;
1258 new_client->driver = &maven_driver;
1259 new_client->flags = 0;
1260 strlcpy(new_client->name, "maven", I2C_NAME_SIZE);
1261 if ((err = i2c_attach_client(new_client)))
1263 err = maven_init_client(new_client);
1268 i2c_detach_client(new_client);
1275 static int maven_attach_adapter(struct i2c_adapter* adapter) {
1276 if (adapter->id == I2C_HW_B_G400)
1277 return i2c_probe(adapter, &addr_data, &maven_detect_client);
1281 static int maven_detach_client(struct i2c_client* client) {
1284 if ((err = i2c_detach_client(client)))
1286 maven_shutdown_client(client);
1287 kfree(i2c_get_clientdata(client));
1291 static struct i2c_driver maven_driver={
1295 .id = I2C_DRIVERID_MGATVO,
1296 .attach_adapter = maven_attach_adapter,
1297 .detach_client = maven_detach_client,
1300 static int __init matroxfb_maven_init(void)
1302 return i2c_add_driver(&maven_driver);
1305 static void __exit matroxfb_maven_exit(void)
1307 i2c_del_driver(&maven_driver);
1310 MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1311 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1312 MODULE_LICENSE("GPL");
1313 module_init(matroxfb_maven_init);
1314 module_exit(matroxfb_maven_exit);
1315 /* we do not have __setup() yet */