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");
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) {
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++) {
718 unsigned int a, b, c, h2;
719 unsigned int h = ht + 2 + x;
721 if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
722 unsigned int diff = h - h2;
726 m->regs[0x80] = a - 1;
727 m->regs[0x81] = b - 1;
728 m->regs[0x82] = c | 0x80;
737 static inline int maven_compute_timming(struct maven_data* md,
738 struct my_timming* mt,
739 struct mavenregs* m) {
741 unsigned int a, bv, c;
742 MINFO_FROM(md->primary_head);
744 m->mode = ACCESS_FBINFO(outputs[1]).mode;
745 if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
746 unsigned int lmargin;
747 unsigned int umargin;
752 maven_init_TVdata(md, m);
754 if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
757 lmargin = mt->HTotal - mt->HSyncEnd;
758 slen = mt->HSyncEnd - mt->HSyncStart;
759 hcrt = mt->HTotal - slen - mt->delay;
760 umargin = mt->VTotal - mt->VSyncEnd;
761 vslen = mt->VSyncEnd - mt->VSyncStart;
763 if (m->hcorr < mt->HTotal)
765 if (hcrt > mt->HTotal)
767 if (hcrt + 2 > mt->HTotal)
768 hcrt = 0; /* or issue warning? */
770 /* last (first? middle?) line in picture can have different length */
772 m->regs[0x96] = m->hcorr;
773 m->regs[0x97] = m->hcorr >> 8;
775 m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
777 m->regs[0x9A] = lmargin; /* 100% */
778 m->regs[0x9B] = lmargin >> 8; /* 100% */
780 m->regs[0x9C] = 0x04;
781 m->regs[0x9D] = 0x00;
783 m->regs[0xA0] = m->htotal;
784 m->regs[0xA1] = m->htotal >> 8;
786 m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */
787 m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
788 /* something end... [A6]+1..[A8] */
789 if (md->version == MGATVO_B) {
790 m->regs[0xA4] = 0x04;
791 m->regs[0xA5] = 0x00;
793 m->regs[0xA4] = 0x01;
794 m->regs[0xA5] = 0x00;
796 /* something start... 0..[A4]-1 */
797 m->regs[0xA6] = 0x00;
798 m->regs[0xA7] = 0x00;
799 /* vertical line count - 1 */
800 m->regs[0xA8] = mt->VTotal - 1;
801 m->regs[0xA9] = (mt->VTotal - 1) >> 8;
802 /* horizontal vidrst pos */
803 m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */
804 m->regs[0xAB] = hcrt >> 8;
805 /* vertical vidrst pos */
806 m->regs[0xAC] = mt->VTotal - 2;
807 m->regs[0xAD] = (mt->VTotal - 2) >> 8;
808 /* moves picture up/down and so on... */
809 m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
810 m->regs[0xAF] = 0x00;
814 unsigned int ibmin = 4 + lmargin + mt->HDisplay;
819 /* Where 94208 came from? */
821 hdec = 94208 / (mt->HTotal);
829 hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
835 /* Now we have to compute input buffer length.
836 If you want any picture, it must be between
840 If you want perfect picture even on the top
841 of screen, it must be also
842 0x3C0000 * i / hdec + Q - R / hdec
852 ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
854 } while (ib < ibmin);
855 if (ib >= m->htotal + 2) {
859 m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
860 m->regs[0xC2] = hlen;
861 /* 'valid' input line length */
863 m->regs[0x9F] = ib >> 8;
869 #define MATROX_USE64BIT_DIVIDE
871 #ifdef MATROX_USE64BIT_DIVIDE
876 a = m->vlines * (m->htotal + 2);
877 b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
879 f1 = ((u64)a) << 15; /* *32768 */
883 vdec = m->vlines * 32768 / mt->VTotal;
889 vlen = (vslen + umargin + mt->VDisplay) * vdec;
890 vlen = (vlen >> 16) - 146; /* FIXME: 146?! */
896 m->regs[0x91] = vdec;
897 m->regs[0x92] = vdec >> 8;
898 m->regs[0xBE] = vlen;
900 m->regs[0xB0] = 0x08; /* output: SVideo/Composite */
904 DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
907 m->regs[0x82] = c | 0x80;
909 m->regs[0xB3] = 0x01;
910 m->regs[0x94] = 0xB2;
913 m->regs[0x96] = mt->HTotal;
914 m->regs[0x97] = mt->HTotal >> 8;
916 m->regs[0x98] = 0x00;
917 m->regs[0x99] = 0x00;
919 tmpi = mt->HSyncEnd - mt->HSyncStart;
920 m->regs[0x9A] = tmpi;
921 m->regs[0x9B] = tmpi >> 8;
923 tmpi = mt->HTotal - mt->HSyncStart;
924 m->regs[0x9C] = tmpi;
925 m->regs[0x9D] = tmpi >> 8;
927 tmpi += mt->HDisplay;
928 m->regs[0x9E] = tmpi;
929 m->regs[0x9F] = tmpi >> 8;
931 tmpi = mt->HTotal + 1;
932 m->regs[0xA0] = tmpi;
933 m->regs[0xA1] = tmpi >> 8;
935 tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
936 m->regs[0xA2] = tmpi;
937 m->regs[0xA3] = tmpi >> 8;
939 tmpi = mt->VTotal - mt->VSyncStart;
940 m->regs[0xA4] = tmpi;
941 m->regs[0xA5] = tmpi >> 8;
943 tmpi = mt->VTotal - 1;
944 m->regs[0xA6] = tmpi;
945 m->regs[0xA7] = tmpi >> 8;
947 m->regs[0xA8] = tmpi;
948 m->regs[0xA9] = tmpi >> 8;
950 tmpi = mt->HTotal - mt->delay;
951 m->regs[0xAA] = tmpi;
952 m->regs[0xAB] = tmpi >> 8;
954 tmpi = mt->VTotal - 2;
955 m->regs[0xAC] = tmpi;
956 m->regs[0xAD] = tmpi >> 8;
958 m->regs[0xAE] = 0x00;
959 m->regs[0xAF] = 0x00;
961 m->regs[0xB0] = 0x03; /* output: monitor */
962 m->regs[0xB1] = 0xA0; /* ??? */
963 m->regs[0x8C] = 0x20; /* must be set... */
964 m->regs[0x8D] = 0x04; /* defaults to 0x10: test signal */
965 m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
966 m->regs[0xBF] = 0x22; /* makes picture stable */
971 static int maven_program_timming(struct maven_data* md,
972 const struct mavenregs* m) {
973 struct i2c_client* c = &md->client;
975 if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
997 LR(0xB0); /* output: monitor */
999 LR(0x8C); /* must be set... */
1000 LR(0x8D); /* defaults to 0x10: test signal */
1001 LR(0xB9); /* defaults to 0x2C: too bright */
1002 LR(0xBF); /* makes picture stable */
1004 maven_init_TV(c, m);
1009 static inline int maven_resync(struct maven_data* md) {
1010 struct i2c_client* c = &md->client;
1011 maven_set_reg(c, 0x95, 0x20); /* start whole thing */
1015 static int maven_get_queryctrl (struct maven_data* md,
1016 struct v4l2_queryctrl *p) {
1019 i = get_ctrl_id(p->id);
1021 *p = maven_controls[i].desc;
1025 static const struct v4l2_queryctrl disctrl =
1026 { .flags = V4L2_CTRL_FLAG_DISABLED };
1031 sprintf(p->name, "Ctrl #%08X", i);
1037 static int maven_set_control (struct maven_data* md,
1038 struct v4l2_control *p) {
1041 i = get_ctrl_id(p->id);
1042 if (i < 0) return -EINVAL;
1047 if (p->value == *get_ctrl_ptr(md, i)) return 0;
1052 if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
1053 if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
1058 *get_ctrl_ptr(md, i) = p->value;
1061 case V4L2_CID_BRIGHTNESS:
1062 case V4L2_CID_CONTRAST:
1064 int blacklevel, whitelevel;
1065 maven_compute_bwlevel(md, &blacklevel, &whitelevel);
1066 blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
1067 whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
1068 maven_set_reg_pair(&md->client, 0x0e, blacklevel);
1069 maven_set_reg_pair(&md->client, 0x1e, whitelevel);
1072 case V4L2_CID_SATURATION:
1074 maven_set_reg(&md->client, 0x20, p->value);
1075 maven_set_reg(&md->client, 0x22, p->value);
1080 maven_set_reg(&md->client, 0x25, p->value);
1083 case V4L2_CID_GAMMA:
1085 const struct maven_gamma* g;
1086 g = maven_compute_gamma(md);
1087 maven_set_reg(&md->client, 0x83, g->reg83);
1088 maven_set_reg(&md->client, 0x84, g->reg84);
1089 maven_set_reg(&md->client, 0x85, g->reg85);
1090 maven_set_reg(&md->client, 0x86, g->reg86);
1091 maven_set_reg(&md->client, 0x87, g->reg87);
1092 maven_set_reg(&md->client, 0x88, g->reg88);
1093 maven_set_reg(&md->client, 0x89, g->reg89);
1094 maven_set_reg(&md->client, 0x8a, g->reg8a);
1095 maven_set_reg(&md->client, 0x8b, g->reg8b);
1098 case MATROXFB_CID_TESTOUT:
1101 = maven_get_reg(&md->client,0x8d);
1102 if (p->value) val |= 0x10;
1104 maven_set_reg(&md->client, 0x8d, val);
1107 case MATROXFB_CID_DEFLICKER:
1109 maven_set_reg(&md->client, 0x93, maven_compute_deflicker(md));
1118 static int maven_get_control (struct maven_data* md,
1119 struct v4l2_control *p) {
1122 i = get_ctrl_id(p->id);
1123 if (i < 0) return -EINVAL;
1124 p->value = *get_ctrl_ptr(md, i);
1128 /******************************************************/
1130 static int maven_out_compute(void* md, struct my_timming* mt) {
1131 #define mdinfo ((struct maven_data*)md)
1132 #define minfo (mdinfo->primary_head)
1133 return maven_compute_timming(md, mt, &ACCESS_FBINFO(hw).maven);
1138 static int maven_out_program(void* md) {
1139 #define mdinfo ((struct maven_data*)md)
1140 #define minfo (mdinfo->primary_head)
1141 return maven_program_timming(md, &ACCESS_FBINFO(hw).maven);
1146 static int maven_out_start(void* md) {
1147 return maven_resync(md);
1150 static int maven_out_verify_mode(void* md, u_int32_t arg) {
1152 case MATROXFB_OUTPUT_MODE_PAL:
1153 case MATROXFB_OUTPUT_MODE_NTSC:
1154 case MATROXFB_OUTPUT_MODE_MONITOR:
1160 static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) {
1161 return maven_get_queryctrl(md, p);
1164 static int maven_out_get_ctrl(void* md, struct v4l2_control* p) {
1165 return maven_get_control(md, p);
1168 static int maven_out_set_ctrl(void* md, struct v4l2_control* p) {
1169 return maven_set_control(md, p);
1172 static struct matrox_altout maven_altout = {
1173 .name = "Secondary output",
1174 .compute = maven_out_compute,
1175 .program = maven_out_program,
1176 .start = maven_out_start,
1177 .verifymode = maven_out_verify_mode,
1178 .getqueryctrl = maven_out_get_queryctrl,
1179 .getctrl = maven_out_get_ctrl,
1180 .setctrl = maven_out_set_ctrl,
1183 static int maven_init_client(struct i2c_client* clnt) {
1184 struct maven_data* md = i2c_get_clientdata(clnt);
1185 MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo);
1187 md->primary_head = MINFO;
1188 down_write(&ACCESS_FBINFO(altout.lock));
1189 ACCESS_FBINFO(outputs[1]).output = &maven_altout;
1190 ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src;
1191 ACCESS_FBINFO(outputs[1]).data = md;
1192 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1193 up_write(&ACCESS_FBINFO(altout.lock));
1194 if (maven_get_reg(clnt, 0xB2) < 0x14) {
1195 md->version = MGATVO_B;
1196 /* Tweak some things for this old chip */
1198 md->version = MGATVO_C;
1201 * Set all parameters to its initial values.
1206 for (i = 0; i < MAVCTRLS; ++i) {
1207 *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
1214 static int maven_shutdown_client(struct i2c_client* clnt) {
1215 struct maven_data* md = i2c_get_clientdata(clnt);
1217 if (md->primary_head) {
1218 MINFO_FROM(md->primary_head);
1220 down_write(&ACCESS_FBINFO(altout.lock));
1221 ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
1222 ACCESS_FBINFO(outputs[1]).output = NULL;
1223 ACCESS_FBINFO(outputs[1]).data = NULL;
1224 ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
1225 up_write(&ACCESS_FBINFO(altout.lock));
1226 md->primary_head = NULL;
1231 static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END };
1234 static struct i2c_driver maven_driver;
1236 static int maven_detect_client(struct i2c_adapter* adapter, int address, int kind) {
1238 struct i2c_client* new_client;
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 new_client = &data->client;
1250 i2c_set_clientdata(new_client, data);
1251 new_client->addr = address;
1252 new_client->adapter = adapter;
1253 new_client->driver = &maven_driver;
1254 new_client->flags = 0;
1255 strlcpy(new_client->name, "maven", I2C_NAME_SIZE);
1256 if ((err = i2c_attach_client(new_client)))
1258 err = maven_init_client(new_client);
1263 i2c_detach_client(new_client);
1270 static int maven_attach_adapter(struct i2c_adapter* adapter) {
1271 if (adapter->id == I2C_HW_B_G400)
1272 return i2c_probe(adapter, &addr_data, &maven_detect_client);
1276 static int maven_detach_client(struct i2c_client* client) {
1279 if ((err = i2c_detach_client(client)))
1281 maven_shutdown_client(client);
1282 kfree(i2c_get_clientdata(client));
1286 static struct i2c_driver maven_driver={
1290 .id = I2C_DRIVERID_MGATVO,
1291 .attach_adapter = maven_attach_adapter,
1292 .detach_client = maven_detach_client,
1295 static int __init matroxfb_maven_init(void)
1297 return i2c_add_driver(&maven_driver);
1300 static void __exit matroxfb_maven_exit(void)
1302 i2c_del_driver(&maven_driver);
1305 MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1306 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1307 MODULE_LICENSE("GPL");
1308 module_init(matroxfb_maven_init);
1309 module_exit(matroxfb_maven_exit);
1310 /* we do not have __setup() yet */