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 <linux/slab.h>
21 #include <asm/div64.h>
26 static const struct maven_gamma
{
37 { 131, 57, 223, 15, 117, 212, 251, 91, 156},
38 { 133, 61, 128, 63, 180, 147, 195, 100, 180},
39 { 131, 19, 63, 31, 50, 66, 171, 64, 176},
40 { 0, 0, 0, 31, 16, 16, 16, 100, 200},
41 { 8, 23, 47, 73, 147, 244, 220, 80, 195},
42 { 22, 43, 64, 80, 147, 115, 58, 85, 168},
43 { 34, 60, 80, 214, 147, 212, 188, 85, 167},
44 { 45, 77, 96, 216, 147, 99, 91, 85, 159},
45 { 56, 76, 112, 107, 147, 212, 148, 64, 144},
46 { 65, 91, 128, 137, 147, 196, 17, 69, 148},
47 { 72, 104, 136, 138, 147, 180, 245, 73, 147},
48 { 87, 116, 143, 126, 16, 83, 229, 77, 144},
49 { 95, 119, 152, 254, 244, 83, 221, 77, 151},
50 { 100, 129, 159, 156, 244, 148, 197, 77, 160},
51 { 105, 141, 167, 247, 244, 132, 181, 84, 166},
52 { 105, 147, 168, 247, 244, 245, 181, 90, 170},
53 { 120, 153, 175, 248, 212, 229, 165, 90, 180},
54 { 119, 156, 176, 248, 244, 229, 84, 74, 160},
55 { 119, 158, 183, 248, 244, 229, 149, 78, 165}
58 /* Definition of the various controls */
60 struct v4l2_queryctrl desc
;
67 static const struct mctl maven_controls
[] =
68 { { { V4L2_CID_BRIGHTNESS
, V4L2_CTRL_TYPE_INTEGER
,
70 0, WLMAX
- BLMIN
, 1, 379 - BLMIN
,
72 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.brightness
) },
73 { { V4L2_CID_CONTRAST
, V4L2_CTRL_TYPE_INTEGER
,
77 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.contrast
) },
78 { { V4L2_CID_SATURATION
, V4L2_CTRL_TYPE_INTEGER
,
82 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.saturation
) },
83 { { V4L2_CID_HUE
, V4L2_CTRL_TYPE_INTEGER
,
87 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.hue
) },
88 { { V4L2_CID_GAMMA
, V4L2_CTRL_TYPE_INTEGER
,
90 0, ARRAY_SIZE(maven_gamma
) - 1, 1, 3,
92 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.gamma
) },
93 { { MATROXFB_CID_TESTOUT
, V4L2_CTRL_TYPE_BOOLEAN
,
97 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.testout
) },
98 { { MATROXFB_CID_DEFLICKER
, V4L2_CTRL_TYPE_INTEGER
,
102 }, offsetof(struct matrox_fb_info
, altout
.tvo_params
.deflicker
) },
106 #define MAVCTRLS ARRAY_SIZE(maven_controls)
108 /* Return: positive number: id found
109 -EINVAL: id not found, return failure
110 -ENOENT: id not found, create fake disabled control */
111 static int get_ctrl_id(__u32 v4l2_id
) {
114 for (i
= 0; i
< MAVCTRLS
; i
++) {
115 if (v4l2_id
< maven_controls
[i
].desc
.id
) {
116 if (maven_controls
[i
].desc
.id
== 0x08000000) {
121 if (v4l2_id
== maven_controls
[i
].desc
.id
) {
129 struct matrox_fb_info
* primary_head
;
130 struct i2c_client
*client
;
134 static int* get_ctrl_ptr(struct maven_data
* md
, int idx
) {
135 return (int*)((char*)(md
->primary_head
) + maven_controls
[idx
].control
);
138 static int maven_get_reg(struct i2c_client
* c
, char reg
) {
140 struct i2c_msg msgs
[] = {{ c
->addr
, I2C_M_REV_DIR_ADDR
, sizeof(reg
), ®
},
141 { c
->addr
, I2C_M_RD
| I2C_M_NOSTART
, sizeof(dst
), &dst
}};
144 err
= i2c_transfer(c
->adapter
, msgs
, 2);
146 printk(KERN_INFO
"ReadReg(%d) failed\n", reg
);
150 static int maven_set_reg(struct i2c_client
* c
, int reg
, int val
) {
153 err
= i2c_smbus_write_byte_data(c
, reg
, val
);
155 printk(KERN_INFO
"WriteReg(%d) failed\n", reg
);
159 static int maven_set_reg_pair(struct i2c_client
* c
, int reg
, int val
) {
162 err
= i2c_smbus_write_word_data(c
, reg
, val
);
164 printk(KERN_INFO
"WriteRegPair(%d) failed\n", reg
);
168 static const struct matrox_pll_features maven_pll
= {
176 struct matrox_pll_features2
{
177 unsigned int vco_freq_min
;
178 unsigned int vco_freq_max
;
179 unsigned int feed_div_min
;
180 unsigned int feed_div_max
;
181 unsigned int in_div_min
;
182 unsigned int in_div_max
;
183 unsigned int post_shift_max
;
186 struct matrox_pll_ctl
{
187 unsigned int ref_freq
;
191 static const struct matrox_pll_features2 maven1000_pll
= {
199 static const struct matrox_pll_ctl maven_PAL
= {
204 static const struct matrox_pll_ctl maven_NTSC
= {
205 450450, /* 27027000/60 == 27000000/59.94005994 */
209 static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2
* pll
,
210 const struct matrox_pll_ctl
* ctl
,
211 unsigned int htotal
, unsigned int vtotal
,
212 unsigned int* in
, unsigned int* feed
, unsigned int* post
,
214 unsigned int besth2
= 0;
215 unsigned int fxtal
= ctl
->ref_freq
;
216 unsigned int fmin
= pll
->vco_freq_min
/ ctl
->den
;
224 scrlen
= htotal
* (vtotal
- 1);
225 fwant
= htotal
* vtotal
;
226 fmax
= pll
->vco_freq_max
/ ctl
->den
;
228 dprintk(KERN_DEBUG
"want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
229 fwant
, fxtal
, htotal
, vtotal
, fmax
);
230 for (p
= 1; p
<= pll
->post_shift_max
; p
++) {
231 if (fwant
* 2 > fmax
)
237 for (; p
-- > 0; fwant
>>= 1) {
240 if (fwant
< fmin
) break;
241 for (m
= pll
->in_div_min
; m
<= pll
->in_div_max
; m
++) {
246 n
= (fwant
* m
) / fxtal
;
247 if (n
< pll
->feed_div_min
)
249 if (n
> pll
->feed_div_max
)
264 dprintk(KERN_DEBUG
"Match: %u / %u / %u / %u\n", n
, m
, p
, ln
);
266 dprintk(KERN_DEBUG
"Better...\n");
275 /* if h2/post/in/feed have not been assigned, return zero (error) */
279 dprintk(KERN_ERR
"clk: %02X %02X %02X %d %d\n", *in
, *feed
, *post
, fxtal
, fwant
);
280 return fxtal
* (*feed
) / (*in
) * ctl
->den
;
283 static int matroxfb_mavenclock(const struct matrox_pll_ctl
*ctl
,
284 unsigned int htotal
, unsigned int vtotal
,
285 unsigned int* in
, unsigned int* feed
, unsigned int* post
,
286 unsigned int* htotal2
) {
288 unsigned int uninitialized_var(p
);
290 fvco
= matroxfb_PLL_mavenclock(&maven1000_pll
, ctl
, htotal
, vtotal
, in
, feed
, &p
, htotal2
);
294 if (fvco
<= 100000000)
296 else if (fvco
<= 140000000)
298 else if (fvco
<= 180000000)
306 static void DAC1064_calcclock(unsigned int freq
, unsigned int fmax
,
307 unsigned int* in
, unsigned int* feed
, unsigned int* post
) {
311 fvco
= matroxfb_PLL_calcclock(&maven_pll
, freq
, fmax
, in
, feed
, &p
);
315 else if (fvco
<= 140000)
317 else if (fvco
<= 180000)
325 static unsigned char maven_compute_deflicker (const struct maven_data
* md
) {
328 df
= (md
->version
== MGATVO_B
?0x40:0x00);
329 switch (md
->primary_head
->altout
.tvo_params
.deflicker
) {
343 static void maven_compute_bwlevel (const struct maven_data
* md
,
345 const int b
= md
->primary_head
->altout
.tvo_params
.brightness
+ BLMIN
;
346 const int c
= md
->primary_head
->altout
.tvo_params
.contrast
;
348 *bl
= max(b
- c
, BLMIN
);
349 *wl
= min(b
+ c
, WLMAX
);
352 static const struct maven_gamma
* maven_compute_gamma (const struct maven_data
* md
) {
353 return maven_gamma
+ md
->primary_head
->altout
.tvo_params
.gamma
;
357 static void maven_init_TVdata(const struct maven_data
* md
, struct mavenregs
* data
) {
358 static struct mavenregs palregs
= { {
359 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
361 0x00, /* ? not written */
362 0x00, /* modified by code (F9 written...) */
363 0x00, /* ? not written */
369 0x00, /* ? not written */
370 0x3F, 0x03, /* 0E-0F */
371 0x3F, 0x03, /* 10-11 */
374 0x1C, 0x3D, 0x14, /* 14-16 */
375 0x9C, 0x01, /* 17-18 */
381 0x89, 0x03, /* 1E-1F */
392 0x55, 0x01, /* 2A-2B */
394 0x07, 0x7E, /* 2D-2E */
395 0x02, 0x54, /* 2F-30 */
396 0xB0, 0x00, /* 31-32 */
399 0x00, /* 35 written multiple times */
400 0x00, /* 36 not written */
406 0x3F, 0x03, /* 3C-3D */
407 0x00, /* 3E written multiple times */
408 0x00, /* 3F not written */
409 }, MATROXFB_OUTPUT_MODE_PAL
, 625, 50 };
410 static struct mavenregs ntscregs
= { {
411 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
413 0x00, /* ? not written */
414 0x00, /* modified by code (F9 written...) */
415 0x00, /* ? not written */
421 0x00, /* ? not written */
422 0x41, 0x00, /* 0E-0F */
423 0x3C, 0x00, /* 10-11 */
426 0x1B, 0x1B, 0x24, /* 14-16 */
427 0x83, 0x01, /* 17-18 */
433 0x89, 0x02, /* 1E-1F */
444 0xFF, 0x03, /* 2A-2B */
446 0x0F, 0x78, /* 2D-2E */
447 0x00, 0x00, /* 2F-30 */
448 0xB2, 0x04, /* 31-32 */
451 0x00, /* 35 written multiple times */
452 0x00, /* 36 not written */
458 0x3C, 0x00, /* 3C-3D */
459 0x00, /* 3E written multiple times */
460 0x00, /* never written */
461 }, MATROXFB_OUTPUT_MODE_NTSC
, 525, 60 };
462 struct matrox_fb_info
*minfo
= md
->primary_head
;
464 if (minfo
->outputs
[1].mode
== MATROXFB_OUTPUT_MODE_PAL
)
470 data
->regs
[0x93] = maven_compute_deflicker(md
);
474 const struct maven_gamma
* g
;
475 g
= maven_compute_gamma(md
);
476 data
->regs
[0x83] = g
->reg83
;
477 data
->regs
[0x84] = g
->reg84
;
478 data
->regs
[0x85] = g
->reg85
;
479 data
->regs
[0x86] = g
->reg86
;
480 data
->regs
[0x87] = g
->reg87
;
481 data
->regs
[0x88] = g
->reg88
;
482 data
->regs
[0x89] = g
->reg89
;
483 data
->regs
[0x8A] = g
->reg8a
;
484 data
->regs
[0x8B] = g
->reg8b
;
487 /* Set contrast / brightness */
490 maven_compute_bwlevel (md
, &bl
, &wl
);
491 data
->regs
[0x0e] = bl
>> 2;
492 data
->regs
[0x0f] = bl
& 3;
493 data
->regs
[0x1e] = wl
>> 2;
494 data
->regs
[0x1f] = wl
& 3;
500 data
->regs
[0x22] = minfo
->altout
.tvo_params
.saturation
;
504 data
->regs
[0x25] = minfo
->altout
.tvo_params
.hue
;
508 #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
509 #define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
510 static void maven_init_TV(struct i2c_client
* c
, const struct mavenregs
* m
) {
514 maven_set_reg(c
, 0x3E, 0x01);
515 maven_get_reg(c
, 0x82); /* fetch oscillator state? */
516 maven_set_reg(c
, 0x8C, 0x00);
517 maven_get_reg(c
, 0x94); /* get 0x82 */
518 maven_set_reg(c
, 0x94, 0xA2);
521 maven_set_reg_pair(c
, 0x8E, 0x1EFF);
522 maven_set_reg(c
, 0xC6, 0x01);
524 /* removed code... */
526 maven_get_reg(c
, 0x06);
527 maven_set_reg(c
, 0x06, 0xF9); /* or read |= 0xF0 ? */
529 /* removed code here... */
531 /* real code begins here? */
532 /* chroma subcarrier */
533 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
546 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
) {
547 maven_set_reg(c
, 0x35, 0x10); /* ... */
549 maven_set_reg(c
, 0x35, 0x0F); /* ... */
557 LR(0x20); /* saturation #1 */
558 LR(0x22); /* saturation #2 */
584 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
)
585 maven_set_reg(c
, 0x35, 0x1D); /* ... */
587 maven_set_reg(c
, 0x35, 0x1C);
592 maven_set_reg(c
, 0xB3, 0x01);
594 maven_get_reg(c
, 0xB0); /* read 0x80 */
595 maven_set_reg(c
, 0xB0, 0x08); /* ugh... */
596 maven_get_reg(c
, 0xB9); /* read 0x7C */
597 maven_set_reg(c
, 0xB9, 0x78);
598 maven_get_reg(c
, 0xBF); /* read 0x00 */
599 maven_set_reg(c
, 0xBF, 0x02);
600 maven_get_reg(c
, 0x94); /* read 0x82 */
601 maven_set_reg(c
, 0x94, 0xB3);
603 LR(0x80); /* 04 1A 91 or 05 21 91 */
607 maven_set_reg(c
, 0x8C, 0x20);
608 maven_get_reg(c
, 0x8D);
609 maven_set_reg(c
, 0x8D, 0x10);
611 LR(0x90); /* 4D 50 52 or 4E 05 45 */
615 LRP(0x9A); /* 0049 or 004F */
616 LRP(0x9C); /* 0004 or 0004 */
617 LRP(0x9E); /* 0458 or 045E */
618 LRP(0xA0); /* 05DA or 051B */
619 LRP(0xA2); /* 00CC or 00CF */
620 LRP(0xA4); /* 007D or 007F */
621 LRP(0xA6); /* 007C or 007E */
622 LRP(0xA8); /* 03CB or 03CE */
623 LRP(0x98); /* 0000 or 0000 */
624 LRP(0xAE); /* 0044 or 003A */
625 LRP(0x96); /* 05DA or 051B */
626 LRP(0xAA); /* 04BC or 046A */
627 LRP(0xAC); /* 004D or 004E */
632 maven_get_reg(c
, 0x8D);
633 maven_set_reg(c
, 0x8D, 0x04);
635 LR(0x20); /* saturation #1 */
636 LR(0x22); /* saturation #2 */
637 LR(0x93); /* whoops */
638 LR(0x20); /* oh, saturation #1 again */
639 LR(0x22); /* oh, saturation #2 again */
643 LRP(0x0E); /* problems with memory? */
644 LRP(0x1E); /* yes, matrox must have problems in memory area... */
646 /* load gamma correction stuff */
657 val
= maven_get_reg(c
, 0x8D);
658 val
&= 0x14; /* 0x10 or anything ored with it */
659 maven_set_reg(c
, 0x8D, val
);
684 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
)
685 maven_set_reg(c
, 0x35, 0x1D);
687 maven_set_reg(c
, 0x35, 0x1C);
692 maven_get_reg(c
, 0xB0);
693 LR(0xB0); /* output mode */
704 maven_set_reg(c
, 0x3E, 0x00);
705 maven_set_reg(c
, 0x95, 0x20);
708 static int maven_find_exact_clocks(unsigned int ht
, unsigned int vt
,
709 struct mavenregs
* m
) {
711 unsigned int err
= ~0;
714 m
->regs
[0x80] = 0x0F;
715 m
->regs
[0x81] = 0x07;
716 m
->regs
[0x82] = 0x81;
718 for (x
= 0; x
< 8; x
++) {
720 unsigned int uninitialized_var(a
), uninitialized_var(b
),
721 uninitialized_var(h2
);
722 unsigned int h
= ht
+ 2 + x
;
724 if (!matroxfb_mavenclock((m
->mode
== MATROXFB_OUTPUT_MODE_PAL
) ? &maven_PAL
: &maven_NTSC
, h
, vt
, &a
, &b
, &c
, &h2
)) {
725 unsigned int diff
= h
- h2
;
729 m
->regs
[0x80] = a
- 1;
730 m
->regs
[0x81] = b
- 1;
731 m
->regs
[0x82] = c
| 0x80;
740 static inline int maven_compute_timming(struct maven_data
* md
,
741 struct my_timming
* mt
,
742 struct mavenregs
* m
) {
744 unsigned int a
, bv
, c
;
745 struct matrox_fb_info
*minfo
= md
->primary_head
;
747 m
->mode
= minfo
->outputs
[1].mode
;
748 if (m
->mode
!= MATROXFB_OUTPUT_MODE_MONITOR
) {
749 unsigned int lmargin
;
750 unsigned int umargin
;
755 maven_init_TVdata(md
, m
);
757 if (maven_find_exact_clocks(mt
->HTotal
, mt
->VTotal
, m
) == 0)
760 lmargin
= mt
->HTotal
- mt
->HSyncEnd
;
761 slen
= mt
->HSyncEnd
- mt
->HSyncStart
;
762 hcrt
= mt
->HTotal
- slen
- mt
->delay
;
763 umargin
= mt
->VTotal
- mt
->VSyncEnd
;
764 vslen
= mt
->VSyncEnd
- mt
->VSyncStart
;
766 if (m
->hcorr
< mt
->HTotal
)
768 if (hcrt
> mt
->HTotal
)
770 if (hcrt
+ 2 > mt
->HTotal
)
771 hcrt
= 0; /* or issue warning? */
773 /* last (first? middle?) line in picture can have different length */
775 m
->regs
[0x96] = m
->hcorr
;
776 m
->regs
[0x97] = m
->hcorr
>> 8;
778 m
->regs
[0x98] = 0x00; m
->regs
[0x99] = 0x00;
780 m
->regs
[0x9A] = lmargin
; /* 100% */
781 m
->regs
[0x9B] = lmargin
>> 8; /* 100% */
783 m
->regs
[0x9C] = 0x04;
784 m
->regs
[0x9D] = 0x00;
786 m
->regs
[0xA0] = m
->htotal
;
787 m
->regs
[0xA1] = m
->htotal
>> 8;
789 m
->regs
[0xA2] = mt
->VTotal
- mt
->VSyncStart
- 1; /* stop vblanking */
790 m
->regs
[0xA3] = (mt
->VTotal
- mt
->VSyncStart
- 1) >> 8;
791 /* something end... [A6]+1..[A8] */
792 if (md
->version
== MGATVO_B
) {
793 m
->regs
[0xA4] = 0x04;
794 m
->regs
[0xA5] = 0x00;
796 m
->regs
[0xA4] = 0x01;
797 m
->regs
[0xA5] = 0x00;
799 /* something start... 0..[A4]-1 */
800 m
->regs
[0xA6] = 0x00;
801 m
->regs
[0xA7] = 0x00;
802 /* vertical line count - 1 */
803 m
->regs
[0xA8] = mt
->VTotal
- 1;
804 m
->regs
[0xA9] = (mt
->VTotal
- 1) >> 8;
805 /* horizontal vidrst pos */
806 m
->regs
[0xAA] = hcrt
; /* 0 <= hcrt <= htotal - 2 */
807 m
->regs
[0xAB] = hcrt
>> 8;
808 /* vertical vidrst pos */
809 m
->regs
[0xAC] = mt
->VTotal
- 2;
810 m
->regs
[0xAD] = (mt
->VTotal
- 2) >> 8;
811 /* moves picture up/down and so on... */
812 m
->regs
[0xAE] = 0x01; /* Fix this... 0..VTotal */
813 m
->regs
[0xAF] = 0x00;
817 unsigned int ibmin
= 4 + lmargin
+ mt
->HDisplay
;
822 /* Where 94208 came from? */
824 hdec
= 94208 / (mt
->HTotal
);
832 hlen
= 98304 - 128 - ((lmargin
+ mt
->HDisplay
- 8) * hdec
);
838 /* Now we have to compute input buffer length.
839 If you want any picture, it must be between
843 If you want perfect picture even on the top
844 of screen, it must be also
845 0x3C0000 * i / hdec + Q - R / hdec
855 ib
= ((0x3C0000 * i
- 0x8000)/ hdec
+ 0x05E7) >> 8;
857 } while (ib
< ibmin
);
858 if (ib
>= m
->htotal
+ 2) {
862 m
->regs
[0x90] = hdec
; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
863 m
->regs
[0xC2] = hlen
;
864 /* 'valid' input line length */
866 m
->regs
[0x9F] = ib
>> 8;
872 #define MATROX_USE64BIT_DIVIDE
874 #ifdef MATROX_USE64BIT_DIVIDE
879 a
= m
->vlines
* (m
->htotal
+ 2);
880 b
= (mt
->VTotal
- 1) * (m
->htotal
+ 2) + m
->hcorr
+ 2;
882 f1
= ((u64
)a
) << 15; /* *32768 */
886 vdec
= m
->vlines
* 32768 / mt
->VTotal
;
892 vlen
= (vslen
+ umargin
+ mt
->VDisplay
) * vdec
;
893 vlen
= (vlen
>> 16) - 146; /* FIXME: 146?! */
899 m
->regs
[0x91] = vdec
;
900 m
->regs
[0x92] = vdec
>> 8;
901 m
->regs
[0xBE] = vlen
;
903 m
->regs
[0xB0] = 0x08; /* output: SVideo/Composite */
907 DAC1064_calcclock(mt
->pixclock
, 450000, &a
, &bv
, &c
);
910 m
->regs
[0x82] = c
| 0x80;
912 m
->regs
[0xB3] = 0x01;
913 m
->regs
[0x94] = 0xB2;
916 m
->regs
[0x96] = mt
->HTotal
;
917 m
->regs
[0x97] = mt
->HTotal
>> 8;
919 m
->regs
[0x98] = 0x00;
920 m
->regs
[0x99] = 0x00;
922 tmpi
= mt
->HSyncEnd
- mt
->HSyncStart
;
923 m
->regs
[0x9A] = tmpi
;
924 m
->regs
[0x9B] = tmpi
>> 8;
926 tmpi
= mt
->HTotal
- mt
->HSyncStart
;
927 m
->regs
[0x9C] = tmpi
;
928 m
->regs
[0x9D] = tmpi
>> 8;
930 tmpi
+= mt
->HDisplay
;
931 m
->regs
[0x9E] = tmpi
;
932 m
->regs
[0x9F] = tmpi
>> 8;
934 tmpi
= mt
->HTotal
+ 1;
935 m
->regs
[0xA0] = tmpi
;
936 m
->regs
[0xA1] = tmpi
>> 8;
938 tmpi
= mt
->VSyncEnd
- mt
->VSyncStart
- 1;
939 m
->regs
[0xA2] = tmpi
;
940 m
->regs
[0xA3] = tmpi
>> 8;
942 tmpi
= mt
->VTotal
- mt
->VSyncStart
;
943 m
->regs
[0xA4] = tmpi
;
944 m
->regs
[0xA5] = tmpi
>> 8;
946 tmpi
= mt
->VTotal
- 1;
947 m
->regs
[0xA6] = tmpi
;
948 m
->regs
[0xA7] = tmpi
>> 8;
950 m
->regs
[0xA8] = tmpi
;
951 m
->regs
[0xA9] = tmpi
>> 8;
953 tmpi
= mt
->HTotal
- mt
->delay
;
954 m
->regs
[0xAA] = tmpi
;
955 m
->regs
[0xAB] = tmpi
>> 8;
957 tmpi
= mt
->VTotal
- 2;
958 m
->regs
[0xAC] = tmpi
;
959 m
->regs
[0xAD] = tmpi
>> 8;
961 m
->regs
[0xAE] = 0x00;
962 m
->regs
[0xAF] = 0x00;
964 m
->regs
[0xB0] = 0x03; /* output: monitor */
965 m
->regs
[0xB1] = 0xA0; /* ??? */
966 m
->regs
[0x8C] = 0x20; /* must be set... */
967 m
->regs
[0x8D] = 0x04; /* defaults to 0x10: test signal */
968 m
->regs
[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
969 m
->regs
[0xBF] = 0x22; /* makes picture stable */
974 static int maven_program_timming(struct maven_data
* md
,
975 const struct mavenregs
* m
) {
976 struct i2c_client
*c
= md
->client
;
978 if (m
->mode
== MATROXFB_OUTPUT_MODE_MONITOR
) {
1000 LR(0xB0); /* output: monitor */
1002 LR(0x8C); /* must be set... */
1003 LR(0x8D); /* defaults to 0x10: test signal */
1004 LR(0xB9); /* defaults to 0x2C: too bright */
1005 LR(0xBF); /* makes picture stable */
1007 maven_init_TV(c
, m
);
1012 static inline int maven_resync(struct maven_data
* md
) {
1013 struct i2c_client
*c
= md
->client
;
1014 maven_set_reg(c
, 0x95, 0x20); /* start whole thing */
1018 static int maven_get_queryctrl (struct maven_data
* md
,
1019 struct v4l2_queryctrl
*p
) {
1022 i
= get_ctrl_id(p
->id
);
1024 *p
= maven_controls
[i
].desc
;
1028 static const struct v4l2_queryctrl disctrl
=
1029 { .flags
= V4L2_CTRL_FLAG_DISABLED
};
1034 sprintf(p
->name
, "Ctrl #%08X", i
);
1040 static int maven_set_control (struct maven_data
* md
,
1041 struct v4l2_control
*p
) {
1044 i
= get_ctrl_id(p
->id
);
1045 if (i
< 0) return -EINVAL
;
1050 if (p
->value
== *get_ctrl_ptr(md
, i
)) return 0;
1055 if (p
->value
> maven_controls
[i
].desc
.maximum
) return -EINVAL
;
1056 if (p
->value
< maven_controls
[i
].desc
.minimum
) return -EINVAL
;
1061 *get_ctrl_ptr(md
, i
) = p
->value
;
1064 case V4L2_CID_BRIGHTNESS
:
1065 case V4L2_CID_CONTRAST
:
1067 int blacklevel
, whitelevel
;
1068 maven_compute_bwlevel(md
, &blacklevel
, &whitelevel
);
1069 blacklevel
= (blacklevel
>> 2) | ((blacklevel
& 3) << 8);
1070 whitelevel
= (whitelevel
>> 2) | ((whitelevel
& 3) << 8);
1071 maven_set_reg_pair(md
->client
, 0x0e, blacklevel
);
1072 maven_set_reg_pair(md
->client
, 0x1e, whitelevel
);
1075 case V4L2_CID_SATURATION
:
1077 maven_set_reg(md
->client
, 0x20, p
->value
);
1078 maven_set_reg(md
->client
, 0x22, p
->value
);
1083 maven_set_reg(md
->client
, 0x25, p
->value
);
1086 case V4L2_CID_GAMMA
:
1088 const struct maven_gamma
* g
;
1089 g
= maven_compute_gamma(md
);
1090 maven_set_reg(md
->client
, 0x83, g
->reg83
);
1091 maven_set_reg(md
->client
, 0x84, g
->reg84
);
1092 maven_set_reg(md
->client
, 0x85, g
->reg85
);
1093 maven_set_reg(md
->client
, 0x86, g
->reg86
);
1094 maven_set_reg(md
->client
, 0x87, g
->reg87
);
1095 maven_set_reg(md
->client
, 0x88, g
->reg88
);
1096 maven_set_reg(md
->client
, 0x89, g
->reg89
);
1097 maven_set_reg(md
->client
, 0x8a, g
->reg8a
);
1098 maven_set_reg(md
->client
, 0x8b, g
->reg8b
);
1101 case MATROXFB_CID_TESTOUT
:
1104 = maven_get_reg(md
->client
, 0x8d);
1105 if (p
->value
) val
|= 0x10;
1107 maven_set_reg(md
->client
, 0x8d, val
);
1110 case MATROXFB_CID_DEFLICKER
:
1112 maven_set_reg(md
->client
, 0x93, maven_compute_deflicker(md
));
1121 static int maven_get_control (struct maven_data
* md
,
1122 struct v4l2_control
*p
) {
1125 i
= get_ctrl_id(p
->id
);
1126 if (i
< 0) return -EINVAL
;
1127 p
->value
= *get_ctrl_ptr(md
, i
);
1131 /******************************************************/
1133 static int maven_out_compute(void* md
, struct my_timming
* mt
) {
1134 #define mdinfo ((struct maven_data*)md)
1135 #define minfo (mdinfo->primary_head)
1136 return maven_compute_timming(md
, mt
, &minfo
->hw
.maven
);
1141 static int maven_out_program(void* md
) {
1142 #define mdinfo ((struct maven_data*)md)
1143 #define minfo (mdinfo->primary_head)
1144 return maven_program_timming(md
, &minfo
->hw
.maven
);
1149 static int maven_out_start(void* md
) {
1150 return maven_resync(md
);
1153 static int maven_out_verify_mode(void* md
, u_int32_t arg
) {
1155 case MATROXFB_OUTPUT_MODE_PAL
:
1156 case MATROXFB_OUTPUT_MODE_NTSC
:
1157 case MATROXFB_OUTPUT_MODE_MONITOR
:
1163 static int maven_out_get_queryctrl(void* md
, struct v4l2_queryctrl
* p
) {
1164 return maven_get_queryctrl(md
, p
);
1167 static int maven_out_get_ctrl(void* md
, struct v4l2_control
* p
) {
1168 return maven_get_control(md
, p
);
1171 static int maven_out_set_ctrl(void* md
, struct v4l2_control
* p
) {
1172 return maven_set_control(md
, p
);
1175 static struct matrox_altout maven_altout
= {
1176 .name
= "Secondary output",
1177 .compute
= maven_out_compute
,
1178 .program
= maven_out_program
,
1179 .start
= maven_out_start
,
1180 .verifymode
= maven_out_verify_mode
,
1181 .getqueryctrl
= maven_out_get_queryctrl
,
1182 .getctrl
= maven_out_get_ctrl
,
1183 .setctrl
= maven_out_set_ctrl
,
1186 static int maven_init_client(struct i2c_client
* clnt
) {
1187 struct maven_data
* md
= i2c_get_clientdata(clnt
);
1188 struct matrox_fb_info
*minfo
= container_of(clnt
->adapter
,
1189 struct i2c_bit_adapter
,
1192 md
->primary_head
= minfo
;
1194 down_write(&minfo
->altout
.lock
);
1195 minfo
->outputs
[1].output
= &maven_altout
;
1196 minfo
->outputs
[1].src
= minfo
->outputs
[1].default_src
;
1197 minfo
->outputs
[1].data
= md
;
1198 minfo
->outputs
[1].mode
= MATROXFB_OUTPUT_MODE_MONITOR
;
1199 up_write(&minfo
->altout
.lock
);
1200 if (maven_get_reg(clnt
, 0xB2) < 0x14) {
1201 md
->version
= MGATVO_B
;
1202 /* Tweak some things for this old chip */
1204 md
->version
= MGATVO_C
;
1207 * Set all parameters to its initial values.
1212 for (i
= 0; i
< MAVCTRLS
; ++i
) {
1213 *get_ctrl_ptr(md
, i
) = maven_controls
[i
].desc
.default_value
;
1220 static int maven_shutdown_client(struct i2c_client
* clnt
) {
1221 struct maven_data
* md
= i2c_get_clientdata(clnt
);
1223 if (md
->primary_head
) {
1224 struct matrox_fb_info
*minfo
= md
->primary_head
;
1226 down_write(&minfo
->altout
.lock
);
1227 minfo
->outputs
[1].src
= MATROXFB_SRC_NONE
;
1228 minfo
->outputs
[1].output
= NULL
;
1229 minfo
->outputs
[1].data
= NULL
;
1230 minfo
->outputs
[1].mode
= MATROXFB_OUTPUT_MODE_MONITOR
;
1231 up_write(&minfo
->altout
.lock
);
1232 md
->primary_head
= NULL
;
1237 static int maven_probe(struct i2c_client
*client
,
1238 const struct i2c_device_id
*id
)
1240 struct i2c_adapter
*adapter
= client
->adapter
;
1242 struct maven_data
* data
;
1244 if (!i2c_check_functionality(adapter
, I2C_FUNC_SMBUS_WRITE_WORD_DATA
|
1245 I2C_FUNC_SMBUS_BYTE_DATA
|
1246 I2C_FUNC_PROTOCOL_MANGLING
))
1248 if (!(data
= kzalloc(sizeof(*data
), GFP_KERNEL
))) {
1252 i2c_set_clientdata(client
, data
);
1253 err
= maven_init_client(client
);
1263 static int maven_remove(struct i2c_client
*client
)
1265 maven_shutdown_client(client
);
1266 kfree(i2c_get_clientdata(client
));
1270 static const struct i2c_device_id maven_id
[] = {
1274 MODULE_DEVICE_TABLE(i2c
, maven_id
);
1276 static struct i2c_driver maven_driver
={
1280 .probe
= maven_probe
,
1281 .remove
= maven_remove
,
1282 .id_table
= maven_id
,
1285 static int __init
matroxfb_maven_init(void)
1287 return i2c_add_driver(&maven_driver
);
1290 static void __exit
matroxfb_maven_exit(void)
1292 i2c_del_driver(&maven_driver
);
1295 MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1296 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1297 MODULE_LICENSE("GPL");
1298 module_init(matroxfb_maven_init
);
1299 module_exit(matroxfb_maven_exit
);
1300 /* we do not have __setup() yet */