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 */