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
[] = {
143 .flags
= I2C_M_REV_DIR_ADDR
,
149 .flags
= I2C_M_RD
| I2C_M_NOSTART
,
156 err
= i2c_transfer(c
->adapter
, msgs
, 2);
158 printk(KERN_INFO
"ReadReg(%d) failed\n", reg
);
162 static int maven_set_reg(struct i2c_client
* c
, int reg
, int val
) {
165 err
= i2c_smbus_write_byte_data(c
, reg
, val
);
167 printk(KERN_INFO
"WriteReg(%d) failed\n", reg
);
171 static int maven_set_reg_pair(struct i2c_client
* c
, int reg
, int val
) {
174 err
= i2c_smbus_write_word_data(c
, reg
, val
);
176 printk(KERN_INFO
"WriteRegPair(%d) failed\n", reg
);
180 static const struct matrox_pll_features maven_pll
= {
188 struct matrox_pll_features2
{
189 unsigned int vco_freq_min
;
190 unsigned int vco_freq_max
;
191 unsigned int feed_div_min
;
192 unsigned int feed_div_max
;
193 unsigned int in_div_min
;
194 unsigned int in_div_max
;
195 unsigned int post_shift_max
;
198 struct matrox_pll_ctl
{
199 unsigned int ref_freq
;
203 static const struct matrox_pll_features2 maven1000_pll
= {
211 static const struct matrox_pll_ctl maven_PAL
= {
216 static const struct matrox_pll_ctl maven_NTSC
= {
217 450450, /* 27027000/60 == 27000000/59.94005994 */
221 static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2
* pll
,
222 const struct matrox_pll_ctl
* ctl
,
223 unsigned int htotal
, unsigned int vtotal
,
224 unsigned int* in
, unsigned int* feed
, unsigned int* post
,
226 unsigned int besth2
= 0;
227 unsigned int fxtal
= ctl
->ref_freq
;
228 unsigned int fmin
= pll
->vco_freq_min
/ ctl
->den
;
236 scrlen
= htotal
* (vtotal
- 1);
237 fwant
= htotal
* vtotal
;
238 fmax
= pll
->vco_freq_max
/ ctl
->den
;
240 dprintk(KERN_DEBUG
"want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
241 fwant
, fxtal
, htotal
, vtotal
, fmax
);
242 for (p
= 1; p
<= pll
->post_shift_max
; p
++) {
243 if (fwant
* 2 > fmax
)
249 for (; p
-- > 0; fwant
>>= 1) {
252 if (fwant
< fmin
) break;
253 for (m
= pll
->in_div_min
; m
<= pll
->in_div_max
; m
++) {
258 n
= (fwant
* m
) / fxtal
;
259 if (n
< pll
->feed_div_min
)
261 if (n
> pll
->feed_div_max
)
276 dprintk(KERN_DEBUG
"Match: %u / %u / %u / %u\n", n
, m
, p
, ln
);
278 dprintk(KERN_DEBUG
"Better...\n");
287 /* if h2/post/in/feed have not been assigned, return zero (error) */
291 dprintk(KERN_ERR
"clk: %02X %02X %02X %d %d\n", *in
, *feed
, *post
, fxtal
, fwant
);
292 return fxtal
* (*feed
) / (*in
) * ctl
->den
;
295 static int matroxfb_mavenclock(const struct matrox_pll_ctl
*ctl
,
296 unsigned int htotal
, unsigned int vtotal
,
297 unsigned int* in
, unsigned int* feed
, unsigned int* post
,
298 unsigned int* htotal2
) {
300 unsigned int uninitialized_var(p
);
302 fvco
= matroxfb_PLL_mavenclock(&maven1000_pll
, ctl
, htotal
, vtotal
, in
, feed
, &p
, htotal2
);
306 if (fvco
<= 100000000)
308 else if (fvco
<= 140000000)
310 else if (fvco
<= 180000000)
318 static void DAC1064_calcclock(unsigned int freq
, unsigned int fmax
,
319 unsigned int* in
, unsigned int* feed
, unsigned int* post
) {
323 fvco
= matroxfb_PLL_calcclock(&maven_pll
, freq
, fmax
, in
, feed
, &p
);
327 else if (fvco
<= 140000)
329 else if (fvco
<= 180000)
337 static unsigned char maven_compute_deflicker (const struct maven_data
* md
) {
340 df
= (md
->version
== MGATVO_B
?0x40:0x00);
341 switch (md
->primary_head
->altout
.tvo_params
.deflicker
) {
355 static void maven_compute_bwlevel (const struct maven_data
* md
,
357 const int b
= md
->primary_head
->altout
.tvo_params
.brightness
+ BLMIN
;
358 const int c
= md
->primary_head
->altout
.tvo_params
.contrast
;
360 *bl
= max(b
- c
, BLMIN
);
361 *wl
= min(b
+ c
, WLMAX
);
364 static const struct maven_gamma
* maven_compute_gamma (const struct maven_data
* md
) {
365 return maven_gamma
+ md
->primary_head
->altout
.tvo_params
.gamma
;
369 static void maven_init_TVdata(const struct maven_data
* md
, struct mavenregs
* data
) {
370 static struct mavenregs palregs
= { {
371 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */
373 0x00, /* ? not written */
374 0x00, /* modified by code (F9 written...) */
375 0x00, /* ? not written */
381 0x00, /* ? not written */
382 0x3F, 0x03, /* 0E-0F */
383 0x3F, 0x03, /* 10-11 */
386 0x1C, 0x3D, 0x14, /* 14-16 */
387 0x9C, 0x01, /* 17-18 */
393 0x89, 0x03, /* 1E-1F */
404 0x55, 0x01, /* 2A-2B */
406 0x07, 0x7E, /* 2D-2E */
407 0x02, 0x54, /* 2F-30 */
408 0xB0, 0x00, /* 31-32 */
411 0x00, /* 35 written multiple times */
412 0x00, /* 36 not written */
418 0x3F, 0x03, /* 3C-3D */
419 0x00, /* 3E written multiple times */
420 0x00, /* 3F not written */
421 }, MATROXFB_OUTPUT_MODE_PAL
, 625, 50 };
422 static struct mavenregs ntscregs
= { {
423 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
425 0x00, /* ? not written */
426 0x00, /* modified by code (F9 written...) */
427 0x00, /* ? not written */
433 0x00, /* ? not written */
434 0x41, 0x00, /* 0E-0F */
435 0x3C, 0x00, /* 10-11 */
438 0x1B, 0x1B, 0x24, /* 14-16 */
439 0x83, 0x01, /* 17-18 */
445 0x89, 0x02, /* 1E-1F */
456 0xFF, 0x03, /* 2A-2B */
458 0x0F, 0x78, /* 2D-2E */
459 0x00, 0x00, /* 2F-30 */
460 0xB2, 0x04, /* 31-32 */
463 0x00, /* 35 written multiple times */
464 0x00, /* 36 not written */
470 0x3C, 0x00, /* 3C-3D */
471 0x00, /* 3E written multiple times */
472 0x00, /* never written */
473 }, MATROXFB_OUTPUT_MODE_NTSC
, 525, 60 };
474 struct matrox_fb_info
*minfo
= md
->primary_head
;
476 if (minfo
->outputs
[1].mode
== MATROXFB_OUTPUT_MODE_PAL
)
482 data
->regs
[0x93] = maven_compute_deflicker(md
);
486 const struct maven_gamma
* g
;
487 g
= maven_compute_gamma(md
);
488 data
->regs
[0x83] = g
->reg83
;
489 data
->regs
[0x84] = g
->reg84
;
490 data
->regs
[0x85] = g
->reg85
;
491 data
->regs
[0x86] = g
->reg86
;
492 data
->regs
[0x87] = g
->reg87
;
493 data
->regs
[0x88] = g
->reg88
;
494 data
->regs
[0x89] = g
->reg89
;
495 data
->regs
[0x8A] = g
->reg8a
;
496 data
->regs
[0x8B] = g
->reg8b
;
499 /* Set contrast / brightness */
502 maven_compute_bwlevel (md
, &bl
, &wl
);
503 data
->regs
[0x0e] = bl
>> 2;
504 data
->regs
[0x0f] = bl
& 3;
505 data
->regs
[0x1e] = wl
>> 2;
506 data
->regs
[0x1f] = wl
& 3;
512 data
->regs
[0x22] = minfo
->altout
.tvo_params
.saturation
;
516 data
->regs
[0x25] = minfo
->altout
.tvo_params
.hue
;
520 #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
521 #define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
522 static void maven_init_TV(struct i2c_client
* c
, const struct mavenregs
* m
) {
526 maven_set_reg(c
, 0x3E, 0x01);
527 maven_get_reg(c
, 0x82); /* fetch oscillator state? */
528 maven_set_reg(c
, 0x8C, 0x00);
529 maven_get_reg(c
, 0x94); /* get 0x82 */
530 maven_set_reg(c
, 0x94, 0xA2);
533 maven_set_reg_pair(c
, 0x8E, 0x1EFF);
534 maven_set_reg(c
, 0xC6, 0x01);
536 /* removed code... */
538 maven_get_reg(c
, 0x06);
539 maven_set_reg(c
, 0x06, 0xF9); /* or read |= 0xF0 ? */
541 /* removed code here... */
543 /* real code begins here? */
544 /* chroma subcarrier */
545 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
558 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
) {
559 maven_set_reg(c
, 0x35, 0x10); /* ... */
561 maven_set_reg(c
, 0x35, 0x0F); /* ... */
569 LR(0x20); /* saturation #1 */
570 LR(0x22); /* saturation #2 */
596 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
)
597 maven_set_reg(c
, 0x35, 0x1D); /* ... */
599 maven_set_reg(c
, 0x35, 0x1C);
604 maven_set_reg(c
, 0xB3, 0x01);
606 maven_get_reg(c
, 0xB0); /* read 0x80 */
607 maven_set_reg(c
, 0xB0, 0x08); /* ugh... */
608 maven_get_reg(c
, 0xB9); /* read 0x7C */
609 maven_set_reg(c
, 0xB9, 0x78);
610 maven_get_reg(c
, 0xBF); /* read 0x00 */
611 maven_set_reg(c
, 0xBF, 0x02);
612 maven_get_reg(c
, 0x94); /* read 0x82 */
613 maven_set_reg(c
, 0x94, 0xB3);
615 LR(0x80); /* 04 1A 91 or 05 21 91 */
619 maven_set_reg(c
, 0x8C, 0x20);
620 maven_get_reg(c
, 0x8D);
621 maven_set_reg(c
, 0x8D, 0x10);
623 LR(0x90); /* 4D 50 52 or 4E 05 45 */
627 LRP(0x9A); /* 0049 or 004F */
628 LRP(0x9C); /* 0004 or 0004 */
629 LRP(0x9E); /* 0458 or 045E */
630 LRP(0xA0); /* 05DA or 051B */
631 LRP(0xA2); /* 00CC or 00CF */
632 LRP(0xA4); /* 007D or 007F */
633 LRP(0xA6); /* 007C or 007E */
634 LRP(0xA8); /* 03CB or 03CE */
635 LRP(0x98); /* 0000 or 0000 */
636 LRP(0xAE); /* 0044 or 003A */
637 LRP(0x96); /* 05DA or 051B */
638 LRP(0xAA); /* 04BC or 046A */
639 LRP(0xAC); /* 004D or 004E */
644 maven_get_reg(c
, 0x8D);
645 maven_set_reg(c
, 0x8D, 0x04);
647 LR(0x20); /* saturation #1 */
648 LR(0x22); /* saturation #2 */
649 LR(0x93); /* whoops */
650 LR(0x20); /* oh, saturation #1 again */
651 LR(0x22); /* oh, saturation #2 again */
655 LRP(0x0E); /* problems with memory? */
656 LRP(0x1E); /* yes, matrox must have problems in memory area... */
658 /* load gamma correction stuff */
669 val
= maven_get_reg(c
, 0x8D);
670 val
&= 0x14; /* 0x10 or anything ored with it */
671 maven_set_reg(c
, 0x8D, val
);
696 if (m
->mode
== MATROXFB_OUTPUT_MODE_PAL
)
697 maven_set_reg(c
, 0x35, 0x1D);
699 maven_set_reg(c
, 0x35, 0x1C);
704 maven_get_reg(c
, 0xB0);
705 LR(0xB0); /* output mode */
716 maven_set_reg(c
, 0x3E, 0x00);
717 maven_set_reg(c
, 0x95, 0x20);
720 static int maven_find_exact_clocks(unsigned int ht
, unsigned int vt
,
721 struct mavenregs
* m
) {
723 unsigned int err
= ~0;
726 m
->regs
[0x80] = 0x0F;
727 m
->regs
[0x81] = 0x07;
728 m
->regs
[0x82] = 0x81;
730 for (x
= 0; x
< 8; x
++) {
732 unsigned int uninitialized_var(a
), uninitialized_var(b
),
733 uninitialized_var(h2
);
734 unsigned int h
= ht
+ 2 + x
;
736 if (!matroxfb_mavenclock((m
->mode
== MATROXFB_OUTPUT_MODE_PAL
) ? &maven_PAL
: &maven_NTSC
, h
, vt
, &a
, &b
, &c
, &h2
)) {
737 unsigned int diff
= h
- h2
;
741 m
->regs
[0x80] = a
- 1;
742 m
->regs
[0x81] = b
- 1;
743 m
->regs
[0x82] = c
| 0x80;
752 static inline int maven_compute_timming(struct maven_data
* md
,
753 struct my_timming
* mt
,
754 struct mavenregs
* m
) {
756 unsigned int a
, bv
, c
;
757 struct matrox_fb_info
*minfo
= md
->primary_head
;
759 m
->mode
= minfo
->outputs
[1].mode
;
760 if (m
->mode
!= MATROXFB_OUTPUT_MODE_MONITOR
) {
761 unsigned int lmargin
;
762 unsigned int umargin
;
767 maven_init_TVdata(md
, m
);
769 if (maven_find_exact_clocks(mt
->HTotal
, mt
->VTotal
, m
) == 0)
772 lmargin
= mt
->HTotal
- mt
->HSyncEnd
;
773 slen
= mt
->HSyncEnd
- mt
->HSyncStart
;
774 hcrt
= mt
->HTotal
- slen
- mt
->delay
;
775 umargin
= mt
->VTotal
- mt
->VSyncEnd
;
776 vslen
= mt
->VSyncEnd
- mt
->VSyncStart
;
778 if (m
->hcorr
< mt
->HTotal
)
780 if (hcrt
> mt
->HTotal
)
782 if (hcrt
+ 2 > mt
->HTotal
)
783 hcrt
= 0; /* or issue warning? */
785 /* last (first? middle?) line in picture can have different length */
787 m
->regs
[0x96] = m
->hcorr
;
788 m
->regs
[0x97] = m
->hcorr
>> 8;
790 m
->regs
[0x98] = 0x00; m
->regs
[0x99] = 0x00;
792 m
->regs
[0x9A] = lmargin
; /* 100% */
793 m
->regs
[0x9B] = lmargin
>> 8; /* 100% */
795 m
->regs
[0x9C] = 0x04;
796 m
->regs
[0x9D] = 0x00;
798 m
->regs
[0xA0] = m
->htotal
;
799 m
->regs
[0xA1] = m
->htotal
>> 8;
801 m
->regs
[0xA2] = mt
->VTotal
- mt
->VSyncStart
- 1; /* stop vblanking */
802 m
->regs
[0xA3] = (mt
->VTotal
- mt
->VSyncStart
- 1) >> 8;
803 /* something end... [A6]+1..[A8] */
804 if (md
->version
== MGATVO_B
) {
805 m
->regs
[0xA4] = 0x04;
806 m
->regs
[0xA5] = 0x00;
808 m
->regs
[0xA4] = 0x01;
809 m
->regs
[0xA5] = 0x00;
811 /* something start... 0..[A4]-1 */
812 m
->regs
[0xA6] = 0x00;
813 m
->regs
[0xA7] = 0x00;
814 /* vertical line count - 1 */
815 m
->regs
[0xA8] = mt
->VTotal
- 1;
816 m
->regs
[0xA9] = (mt
->VTotal
- 1) >> 8;
817 /* horizontal vidrst pos */
818 m
->regs
[0xAA] = hcrt
; /* 0 <= hcrt <= htotal - 2 */
819 m
->regs
[0xAB] = hcrt
>> 8;
820 /* vertical vidrst pos */
821 m
->regs
[0xAC] = mt
->VTotal
- 2;
822 m
->regs
[0xAD] = (mt
->VTotal
- 2) >> 8;
823 /* moves picture up/down and so on... */
824 m
->regs
[0xAE] = 0x01; /* Fix this... 0..VTotal */
825 m
->regs
[0xAF] = 0x00;
829 unsigned int ibmin
= 4 + lmargin
+ mt
->HDisplay
;
834 /* Where 94208 came from? */
836 hdec
= 94208 / (mt
->HTotal
);
844 hlen
= 98304 - 128 - ((lmargin
+ mt
->HDisplay
- 8) * hdec
);
850 /* Now we have to compute input buffer length.
851 If you want any picture, it must be between
855 If you want perfect picture even on the top
856 of screen, it must be also
857 0x3C0000 * i / hdec + Q - R / hdec
867 ib
= ((0x3C0000 * i
- 0x8000)/ hdec
+ 0x05E7) >> 8;
869 } while (ib
< ibmin
);
870 if (ib
>= m
->htotal
+ 2) {
874 m
->regs
[0x90] = hdec
; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
875 m
->regs
[0xC2] = hlen
;
876 /* 'valid' input line length */
878 m
->regs
[0x9F] = ib
>> 8;
884 #define MATROX_USE64BIT_DIVIDE
886 #ifdef MATROX_USE64BIT_DIVIDE
891 a
= m
->vlines
* (m
->htotal
+ 2);
892 b
= (mt
->VTotal
- 1) * (m
->htotal
+ 2) + m
->hcorr
+ 2;
894 f1
= ((u64
)a
) << 15; /* *32768 */
898 vdec
= m
->vlines
* 32768 / mt
->VTotal
;
904 vlen
= (vslen
+ umargin
+ mt
->VDisplay
) * vdec
;
905 vlen
= (vlen
>> 16) - 146; /* FIXME: 146?! */
911 m
->regs
[0x91] = vdec
;
912 m
->regs
[0x92] = vdec
>> 8;
913 m
->regs
[0xBE] = vlen
;
915 m
->regs
[0xB0] = 0x08; /* output: SVideo/Composite */
919 DAC1064_calcclock(mt
->pixclock
, 450000, &a
, &bv
, &c
);
922 m
->regs
[0x82] = c
| 0x80;
924 m
->regs
[0xB3] = 0x01;
925 m
->regs
[0x94] = 0xB2;
928 m
->regs
[0x96] = mt
->HTotal
;
929 m
->regs
[0x97] = mt
->HTotal
>> 8;
931 m
->regs
[0x98] = 0x00;
932 m
->regs
[0x99] = 0x00;
934 tmpi
= mt
->HSyncEnd
- mt
->HSyncStart
;
935 m
->regs
[0x9A] = tmpi
;
936 m
->regs
[0x9B] = tmpi
>> 8;
938 tmpi
= mt
->HTotal
- mt
->HSyncStart
;
939 m
->regs
[0x9C] = tmpi
;
940 m
->regs
[0x9D] = tmpi
>> 8;
942 tmpi
+= mt
->HDisplay
;
943 m
->regs
[0x9E] = tmpi
;
944 m
->regs
[0x9F] = tmpi
>> 8;
946 tmpi
= mt
->HTotal
+ 1;
947 m
->regs
[0xA0] = tmpi
;
948 m
->regs
[0xA1] = tmpi
>> 8;
950 tmpi
= mt
->VSyncEnd
- mt
->VSyncStart
- 1;
951 m
->regs
[0xA2] = tmpi
;
952 m
->regs
[0xA3] = tmpi
>> 8;
954 tmpi
= mt
->VTotal
- mt
->VSyncStart
;
955 m
->regs
[0xA4] = tmpi
;
956 m
->regs
[0xA5] = tmpi
>> 8;
958 tmpi
= mt
->VTotal
- 1;
959 m
->regs
[0xA6] = tmpi
;
960 m
->regs
[0xA7] = tmpi
>> 8;
962 m
->regs
[0xA8] = tmpi
;
963 m
->regs
[0xA9] = tmpi
>> 8;
965 tmpi
= mt
->HTotal
- mt
->delay
;
966 m
->regs
[0xAA] = tmpi
;
967 m
->regs
[0xAB] = tmpi
>> 8;
969 tmpi
= mt
->VTotal
- 2;
970 m
->regs
[0xAC] = tmpi
;
971 m
->regs
[0xAD] = tmpi
>> 8;
973 m
->regs
[0xAE] = 0x00;
974 m
->regs
[0xAF] = 0x00;
976 m
->regs
[0xB0] = 0x03; /* output: monitor */
977 m
->regs
[0xB1] = 0xA0; /* ??? */
978 m
->regs
[0x8C] = 0x20; /* must be set... */
979 m
->regs
[0x8D] = 0x04; /* defaults to 0x10: test signal */
980 m
->regs
[0xB9] = 0x1A; /* defaults to 0x2C: too bright */
981 m
->regs
[0xBF] = 0x22; /* makes picture stable */
986 static int maven_program_timming(struct maven_data
* md
,
987 const struct mavenregs
* m
) {
988 struct i2c_client
*c
= md
->client
;
990 if (m
->mode
== MATROXFB_OUTPUT_MODE_MONITOR
) {
1012 LR(0xB0); /* output: monitor */
1014 LR(0x8C); /* must be set... */
1015 LR(0x8D); /* defaults to 0x10: test signal */
1016 LR(0xB9); /* defaults to 0x2C: too bright */
1017 LR(0xBF); /* makes picture stable */
1019 maven_init_TV(c
, m
);
1024 static inline int maven_resync(struct maven_data
* md
) {
1025 struct i2c_client
*c
= md
->client
;
1026 maven_set_reg(c
, 0x95, 0x20); /* start whole thing */
1030 static int maven_get_queryctrl (struct maven_data
* md
,
1031 struct v4l2_queryctrl
*p
) {
1034 i
= get_ctrl_id(p
->id
);
1036 *p
= maven_controls
[i
].desc
;
1040 static const struct v4l2_queryctrl disctrl
=
1041 { .flags
= V4L2_CTRL_FLAG_DISABLED
};
1046 sprintf(p
->name
, "Ctrl #%08X", i
);
1052 static int maven_set_control (struct maven_data
* md
,
1053 struct v4l2_control
*p
) {
1056 i
= get_ctrl_id(p
->id
);
1057 if (i
< 0) return -EINVAL
;
1062 if (p
->value
== *get_ctrl_ptr(md
, i
)) return 0;
1067 if (p
->value
> maven_controls
[i
].desc
.maximum
) return -EINVAL
;
1068 if (p
->value
< maven_controls
[i
].desc
.minimum
) return -EINVAL
;
1073 *get_ctrl_ptr(md
, i
) = p
->value
;
1076 case V4L2_CID_BRIGHTNESS
:
1077 case V4L2_CID_CONTRAST
:
1079 int blacklevel
, whitelevel
;
1080 maven_compute_bwlevel(md
, &blacklevel
, &whitelevel
);
1081 blacklevel
= (blacklevel
>> 2) | ((blacklevel
& 3) << 8);
1082 whitelevel
= (whitelevel
>> 2) | ((whitelevel
& 3) << 8);
1083 maven_set_reg_pair(md
->client
, 0x0e, blacklevel
);
1084 maven_set_reg_pair(md
->client
, 0x1e, whitelevel
);
1087 case V4L2_CID_SATURATION
:
1089 maven_set_reg(md
->client
, 0x20, p
->value
);
1090 maven_set_reg(md
->client
, 0x22, p
->value
);
1095 maven_set_reg(md
->client
, 0x25, p
->value
);
1098 case V4L2_CID_GAMMA
:
1100 const struct maven_gamma
* g
;
1101 g
= maven_compute_gamma(md
);
1102 maven_set_reg(md
->client
, 0x83, g
->reg83
);
1103 maven_set_reg(md
->client
, 0x84, g
->reg84
);
1104 maven_set_reg(md
->client
, 0x85, g
->reg85
);
1105 maven_set_reg(md
->client
, 0x86, g
->reg86
);
1106 maven_set_reg(md
->client
, 0x87, g
->reg87
);
1107 maven_set_reg(md
->client
, 0x88, g
->reg88
);
1108 maven_set_reg(md
->client
, 0x89, g
->reg89
);
1109 maven_set_reg(md
->client
, 0x8a, g
->reg8a
);
1110 maven_set_reg(md
->client
, 0x8b, g
->reg8b
);
1113 case MATROXFB_CID_TESTOUT
:
1116 = maven_get_reg(md
->client
, 0x8d);
1117 if (p
->value
) val
|= 0x10;
1119 maven_set_reg(md
->client
, 0x8d, val
);
1122 case MATROXFB_CID_DEFLICKER
:
1124 maven_set_reg(md
->client
, 0x93, maven_compute_deflicker(md
));
1133 static int maven_get_control (struct maven_data
* md
,
1134 struct v4l2_control
*p
) {
1137 i
= get_ctrl_id(p
->id
);
1138 if (i
< 0) return -EINVAL
;
1139 p
->value
= *get_ctrl_ptr(md
, i
);
1143 /******************************************************/
1145 static int maven_out_compute(void* md
, struct my_timming
* mt
) {
1146 #define mdinfo ((struct maven_data*)md)
1147 #define minfo (mdinfo->primary_head)
1148 return maven_compute_timming(md
, mt
, &minfo
->hw
.maven
);
1153 static int maven_out_program(void* md
) {
1154 #define mdinfo ((struct maven_data*)md)
1155 #define minfo (mdinfo->primary_head)
1156 return maven_program_timming(md
, &minfo
->hw
.maven
);
1161 static int maven_out_start(void* md
) {
1162 return maven_resync(md
);
1165 static int maven_out_verify_mode(void* md
, u_int32_t arg
) {
1167 case MATROXFB_OUTPUT_MODE_PAL
:
1168 case MATROXFB_OUTPUT_MODE_NTSC
:
1169 case MATROXFB_OUTPUT_MODE_MONITOR
:
1175 static int maven_out_get_queryctrl(void* md
, struct v4l2_queryctrl
* p
) {
1176 return maven_get_queryctrl(md
, p
);
1179 static int maven_out_get_ctrl(void* md
, struct v4l2_control
* p
) {
1180 return maven_get_control(md
, p
);
1183 static int maven_out_set_ctrl(void* md
, struct v4l2_control
* p
) {
1184 return maven_set_control(md
, p
);
1187 static struct matrox_altout maven_altout
= {
1188 .name
= "Secondary output",
1189 .compute
= maven_out_compute
,
1190 .program
= maven_out_program
,
1191 .start
= maven_out_start
,
1192 .verifymode
= maven_out_verify_mode
,
1193 .getqueryctrl
= maven_out_get_queryctrl
,
1194 .getctrl
= maven_out_get_ctrl
,
1195 .setctrl
= maven_out_set_ctrl
,
1198 static int maven_init_client(struct i2c_client
* clnt
) {
1199 struct maven_data
* md
= i2c_get_clientdata(clnt
);
1200 struct matrox_fb_info
*minfo
= container_of(clnt
->adapter
,
1201 struct i2c_bit_adapter
,
1204 md
->primary_head
= minfo
;
1206 down_write(&minfo
->altout
.lock
);
1207 minfo
->outputs
[1].output
= &maven_altout
;
1208 minfo
->outputs
[1].src
= minfo
->outputs
[1].default_src
;
1209 minfo
->outputs
[1].data
= md
;
1210 minfo
->outputs
[1].mode
= MATROXFB_OUTPUT_MODE_MONITOR
;
1211 up_write(&minfo
->altout
.lock
);
1212 if (maven_get_reg(clnt
, 0xB2) < 0x14) {
1213 md
->version
= MGATVO_B
;
1214 /* Tweak some things for this old chip */
1216 md
->version
= MGATVO_C
;
1219 * Set all parameters to its initial values.
1224 for (i
= 0; i
< MAVCTRLS
; ++i
) {
1225 *get_ctrl_ptr(md
, i
) = maven_controls
[i
].desc
.default_value
;
1232 static int maven_shutdown_client(struct i2c_client
* clnt
) {
1233 struct maven_data
* md
= i2c_get_clientdata(clnt
);
1235 if (md
->primary_head
) {
1236 struct matrox_fb_info
*minfo
= md
->primary_head
;
1238 down_write(&minfo
->altout
.lock
);
1239 minfo
->outputs
[1].src
= MATROXFB_SRC_NONE
;
1240 minfo
->outputs
[1].output
= NULL
;
1241 minfo
->outputs
[1].data
= NULL
;
1242 minfo
->outputs
[1].mode
= MATROXFB_OUTPUT_MODE_MONITOR
;
1243 up_write(&minfo
->altout
.lock
);
1244 md
->primary_head
= NULL
;
1249 static int maven_probe(struct i2c_client
*client
,
1250 const struct i2c_device_id
*id
)
1252 struct i2c_adapter
*adapter
= client
->adapter
;
1254 struct maven_data
* data
;
1256 if (!i2c_check_functionality(adapter
, I2C_FUNC_SMBUS_WRITE_WORD_DATA
|
1257 I2C_FUNC_SMBUS_BYTE_DATA
|
1259 I2C_FUNC_PROTOCOL_MANGLING
))
1261 if (!(data
= kzalloc(sizeof(*data
), GFP_KERNEL
))) {
1265 i2c_set_clientdata(client
, data
);
1266 err
= maven_init_client(client
);
1276 static int maven_remove(struct i2c_client
*client
)
1278 maven_shutdown_client(client
);
1279 kfree(i2c_get_clientdata(client
));
1283 static const struct i2c_device_id maven_id
[] = {
1287 MODULE_DEVICE_TABLE(i2c
, maven_id
);
1289 static struct i2c_driver maven_driver
={
1293 .probe
= maven_probe
,
1294 .remove
= maven_remove
,
1295 .id_table
= maven_id
,
1298 module_i2c_driver(maven_driver
);
1299 MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1300 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1301 MODULE_LICENSE("GPL");