0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include "matroxfb_maven.h"
0017 #include "matroxfb_misc.h"
0018 #include "matroxfb_DAC1064.h"
0019 #include <linux/i2c.h>
0020 #include <linux/matroxfb.h>
0021 #include <linux/slab.h>
0022 #include <asm/div64.h>
0023
0024 #define MGATVO_B 1
0025 #define MGATVO_C 2
0026
0027 static const struct maven_gamma {
0028 unsigned char reg83;
0029 unsigned char reg84;
0030 unsigned char reg85;
0031 unsigned char reg86;
0032 unsigned char reg87;
0033 unsigned char reg88;
0034 unsigned char reg89;
0035 unsigned char reg8a;
0036 unsigned char reg8b;
0037 } maven_gamma[] = {
0038 { 131, 57, 223, 15, 117, 212, 251, 91, 156},
0039 { 133, 61, 128, 63, 180, 147, 195, 100, 180},
0040 { 131, 19, 63, 31, 50, 66, 171, 64, 176},
0041 { 0, 0, 0, 31, 16, 16, 16, 100, 200},
0042 { 8, 23, 47, 73, 147, 244, 220, 80, 195},
0043 { 22, 43, 64, 80, 147, 115, 58, 85, 168},
0044 { 34, 60, 80, 214, 147, 212, 188, 85, 167},
0045 { 45, 77, 96, 216, 147, 99, 91, 85, 159},
0046 { 56, 76, 112, 107, 147, 212, 148, 64, 144},
0047 { 65, 91, 128, 137, 147, 196, 17, 69, 148},
0048 { 72, 104, 136, 138, 147, 180, 245, 73, 147},
0049 { 87, 116, 143, 126, 16, 83, 229, 77, 144},
0050 { 95, 119, 152, 254, 244, 83, 221, 77, 151},
0051 { 100, 129, 159, 156, 244, 148, 197, 77, 160},
0052 { 105, 141, 167, 247, 244, 132, 181, 84, 166},
0053 { 105, 147, 168, 247, 244, 245, 181, 90, 170},
0054 { 120, 153, 175, 248, 212, 229, 165, 90, 180},
0055 { 119, 156, 176, 248, 244, 229, 84, 74, 160},
0056 { 119, 158, 183, 248, 244, 229, 149, 78, 165}
0057 };
0058
0059
0060 struct mctl {
0061 struct v4l2_queryctrl desc;
0062 size_t control;
0063 };
0064
0065 #define BLMIN 0x0FF
0066 #define WLMAX 0x3FF
0067
0068 static const struct mctl maven_controls[] =
0069 { { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
0070 "brightness",
0071 0, WLMAX - BLMIN, 1, 379 - BLMIN,
0072 0,
0073 }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
0074 { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
0075 "contrast",
0076 0, 1023, 1, 127,
0077 0,
0078 }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
0079 { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
0080 "saturation",
0081 0, 255, 1, 155,
0082 0,
0083 }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
0084 { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
0085 "hue",
0086 0, 255, 1, 0,
0087 0,
0088 }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
0089 { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER,
0090 "gamma",
0091 0, ARRAY_SIZE(maven_gamma) - 1, 1, 3,
0092 0,
0093 }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
0094 { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
0095 "test output",
0096 0, 1, 1, 0,
0097 0,
0098 }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
0099 { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER,
0100 "deflicker mode",
0101 0, 2, 1, 0,
0102 0,
0103 }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
0104
0105 };
0106
0107 #define MAVCTRLS ARRAY_SIZE(maven_controls)
0108
0109
0110
0111
0112 static int get_ctrl_id(__u32 v4l2_id) {
0113 int i;
0114
0115 for (i = 0; i < MAVCTRLS; i++) {
0116 if (v4l2_id < maven_controls[i].desc.id) {
0117 if (maven_controls[i].desc.id == 0x08000000) {
0118 return -EINVAL;
0119 }
0120 return -ENOENT;
0121 }
0122 if (v4l2_id == maven_controls[i].desc.id) {
0123 return i;
0124 }
0125 }
0126 return -EINVAL;
0127 }
0128
0129 struct maven_data {
0130 struct matrox_fb_info* primary_head;
0131 struct i2c_client *client;
0132 int version;
0133 };
0134
0135 static int* get_ctrl_ptr(struct maven_data* md, int idx) {
0136 return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
0137 }
0138
0139 static int maven_get_reg(struct i2c_client* c, char reg) {
0140 char dst;
0141 struct i2c_msg msgs[] = {
0142 {
0143 .addr = c->addr,
0144 .flags = I2C_M_REV_DIR_ADDR,
0145 .len = sizeof(reg),
0146 .buf = ®
0147 },
0148 {
0149 .addr = c->addr,
0150 .flags = I2C_M_RD | I2C_M_NOSTART,
0151 .len = sizeof(dst),
0152 .buf = &dst
0153 }
0154 };
0155 s32 err;
0156
0157 err = i2c_transfer(c->adapter, msgs, 2);
0158 if (err < 0)
0159 printk(KERN_INFO "ReadReg(%d) failed\n", reg);
0160 return dst & 0xFF;
0161 }
0162
0163 static int maven_set_reg(struct i2c_client* c, int reg, int val) {
0164 s32 err;
0165
0166 err = i2c_smbus_write_byte_data(c, reg, val);
0167 if (err)
0168 printk(KERN_INFO "WriteReg(%d) failed\n", reg);
0169 return err;
0170 }
0171
0172 static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
0173 s32 err;
0174
0175 err = i2c_smbus_write_word_data(c, reg, val);
0176 if (err)
0177 printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
0178 return err;
0179 }
0180
0181 static const struct matrox_pll_features maven_pll = {
0182 50000,
0183 27000,
0184 4, 127,
0185 2, 31,
0186 3
0187 };
0188
0189 struct matrox_pll_features2 {
0190 unsigned int vco_freq_min;
0191 unsigned int vco_freq_max;
0192 unsigned int feed_div_min;
0193 unsigned int feed_div_max;
0194 unsigned int in_div_min;
0195 unsigned int in_div_max;
0196 unsigned int post_shift_max;
0197 };
0198
0199 struct matrox_pll_ctl {
0200 unsigned int ref_freq;
0201 unsigned int den;
0202 };
0203
0204 static const struct matrox_pll_features2 maven1000_pll = {
0205 .vco_freq_min = 50000000,
0206 .vco_freq_max = 300000000,
0207 .feed_div_min = 5,
0208 .feed_div_max = 128,
0209 .in_div_min = 3,
0210 .in_div_max = 32,
0211 .post_shift_max = 3
0212 };
0213
0214 static const struct matrox_pll_ctl maven_PAL = {
0215 .ref_freq = 540000,
0216 .den = 50
0217 };
0218
0219 static const struct matrox_pll_ctl maven_NTSC = {
0220 .ref_freq = 450450,
0221 .den = 60
0222 };
0223
0224 static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
0225 const struct matrox_pll_ctl* ctl,
0226 unsigned int htotal, unsigned int vtotal,
0227 unsigned int* in, unsigned int* feed, unsigned int* post,
0228 unsigned int* h2) {
0229 unsigned int besth2 = 0;
0230 unsigned int fxtal = ctl->ref_freq;
0231 unsigned int fmin = pll->vco_freq_min / ctl->den;
0232 unsigned int fwant;
0233 unsigned int p;
0234 unsigned int scrlen;
0235 unsigned int fmax;
0236
0237 DBG(__func__)
0238
0239 scrlen = htotal * (vtotal - 1);
0240 fwant = htotal * vtotal;
0241 fmax = pll->vco_freq_max / ctl->den;
0242
0243 dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
0244 fwant, fxtal, htotal, vtotal, fmax);
0245 for (p = 1; p <= pll->post_shift_max; p++) {
0246 if (fwant * 2 > fmax)
0247 break;
0248 fwant *= 2;
0249 }
0250 if (fwant > fmax)
0251 return 0;
0252 for (; p-- > 0; fwant >>= 1) {
0253 unsigned int m;
0254
0255 if (fwant < fmin) break;
0256 for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
0257 unsigned int n;
0258 unsigned int dvd;
0259 unsigned int ln;
0260
0261 n = (fwant * m) / fxtal;
0262 if (n < pll->feed_div_min)
0263 continue;
0264 if (n > pll->feed_div_max)
0265 break;
0266
0267 ln = fxtal * n;
0268 dvd = m << p;
0269
0270 if (ln % dvd)
0271 continue;
0272 ln = ln / dvd;
0273
0274 if (ln < scrlen + 2)
0275 continue;
0276 ln = ln - scrlen;
0277 if (ln > htotal)
0278 continue;
0279 dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
0280 if (ln > besth2) {
0281 dprintk(KERN_DEBUG "Better...\n");
0282 *h2 = besth2 = ln;
0283 *post = p;
0284 *in = m;
0285 *feed = n;
0286 }
0287 }
0288 }
0289
0290
0291 if (besth2 < 2)
0292 return 0;
0293
0294 dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
0295 return fxtal * (*feed) / (*in) * ctl->den;
0296 }
0297
0298 static int matroxfb_mavenclock(const struct matrox_pll_ctl *ctl,
0299 unsigned int htotal, unsigned int vtotal,
0300 unsigned int* in, unsigned int* feed, unsigned int* post,
0301 unsigned int* htotal2) {
0302 unsigned int fvco;
0303 unsigned int p;
0304
0305 fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
0306 if (!fvco)
0307 return -EINVAL;
0308 p = (1 << p) - 1;
0309 if (fvco <= 100000000)
0310 ;
0311 else if (fvco <= 140000000)
0312 p |= 0x08;
0313 else if (fvco <= 180000000)
0314 p |= 0x10;
0315 else
0316 p |= 0x18;
0317 *post = p;
0318 return 0;
0319 }
0320
0321 static void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
0322 unsigned int* in, unsigned int* feed, unsigned int* post) {
0323 unsigned int fvco;
0324 unsigned int p;
0325
0326 fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
0327 p = (1 << p) - 1;
0328 if (fvco <= 100000)
0329 ;
0330 else if (fvco <= 140000)
0331 p |= 0x08;
0332 else if (fvco <= 180000)
0333 p |= 0x10;
0334 else
0335 p |= 0x18;
0336 *post = p;
0337 return;
0338 }
0339
0340 static unsigned char maven_compute_deflicker (const struct maven_data* md) {
0341 unsigned char df;
0342
0343 df = (md->version == MGATVO_B?0x40:0x00);
0344 switch (md->primary_head->altout.tvo_params.deflicker) {
0345 case 0:
0346
0347 break;
0348 case 1:
0349 df |= 0xB1;
0350 break;
0351 case 2:
0352 df |= 0xA2;
0353 break;
0354 }
0355 return df;
0356 }
0357
0358 static void maven_compute_bwlevel (const struct maven_data* md,
0359 int *bl, int *wl) {
0360 const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
0361 const int c = md->primary_head->altout.tvo_params.contrast;
0362
0363 *bl = max(b - c, BLMIN);
0364 *wl = min(b + c, WLMAX);
0365 }
0366
0367 static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
0368 return maven_gamma + md->primary_head->altout.tvo_params.gamma;
0369 }
0370
0371
0372 static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
0373 static struct mavenregs palregs = { {
0374 0x2A, 0x09, 0x8A, 0xCB,
0375 0x00,
0376 0x00,
0377 0x00,
0378 0x00,
0379 0x7E,
0380 0x44,
0381 0x9C,
0382 0x2E,
0383 0x21,
0384 0x00,
0385 0x3F, 0x03,
0386 0x3F, 0x03,
0387 0x1A,
0388 0x2A,
0389 0x1C, 0x3D, 0x14,
0390 0x9C, 0x01,
0391 0x00,
0392 0xFE,
0393 0x7E,
0394 0x60,
0395 0x05,
0396 0x89, 0x03,
0397 0x72,
0398 0x07,
0399 0x72,
0400 0x00,
0401 0x00,
0402 0x00,
0403 0x08,
0404 0x04,
0405 0x00,
0406 0x1A,
0407 0x55, 0x01,
0408 0x26,
0409 0x07, 0x7E,
0410 0x02, 0x54,
0411 0xB0, 0x00,
0412 0x14,
0413 0x49,
0414 0x00,
0415 0x00,
0416 0xA3,
0417 0xC8,
0418 0x22,
0419 0x02,
0420 0x22,
0421 0x3F, 0x03,
0422 0x00,
0423 0x00,
0424 }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
0425 static struct mavenregs ntscregs = { {
0426 0x21, 0xF0, 0x7C, 0x1F,
0427 0x00,
0428 0x00,
0429 0x00,
0430 0x00,
0431 0x7E,
0432 0x43,
0433 0x7E,
0434 0x3D,
0435 0x00,
0436 0x00,
0437 0x41, 0x00,
0438 0x3C, 0x00,
0439 0x17,
0440 0x21,
0441 0x1B, 0x1B, 0x24,
0442 0x83, 0x01,
0443 0x00,
0444 0x0F,
0445 0x0F,
0446 0x60,
0447 0x05,
0448 0x89, 0x02,
0449 0x5F,
0450 0x04,
0451 0x5F,
0452 0x01,
0453 0x02,
0454 0x00,
0455 0x0A,
0456 0x05,
0457 0x00,
0458 0x10,
0459 0xFF, 0x03,
0460 0x24,
0461 0x0F, 0x78,
0462 0x00, 0x00,
0463 0xB2, 0x04,
0464 0x14,
0465 0x02,
0466 0x00,
0467 0x00,
0468 0xA3,
0469 0xC8,
0470 0x15,
0471 0x05,
0472 0x3B,
0473 0x3C, 0x00,
0474 0x00,
0475 0x00,
0476 }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
0477 struct matrox_fb_info *minfo = md->primary_head;
0478
0479 if (minfo->outputs[1].mode == MATROXFB_OUTPUT_MODE_PAL)
0480 *data = palregs;
0481 else
0482 *data = ntscregs;
0483
0484
0485 data->regs[0x93] = maven_compute_deflicker(md);
0486
0487
0488 {
0489 const struct maven_gamma* g;
0490 g = maven_compute_gamma(md);
0491 data->regs[0x83] = g->reg83;
0492 data->regs[0x84] = g->reg84;
0493 data->regs[0x85] = g->reg85;
0494 data->regs[0x86] = g->reg86;
0495 data->regs[0x87] = g->reg87;
0496 data->regs[0x88] = g->reg88;
0497 data->regs[0x89] = g->reg89;
0498 data->regs[0x8A] = g->reg8a;
0499 data->regs[0x8B] = g->reg8b;
0500 }
0501
0502
0503 {
0504 int bl, wl;
0505 maven_compute_bwlevel (md, &bl, &wl);
0506 data->regs[0x0e] = bl >> 2;
0507 data->regs[0x0f] = bl & 3;
0508 data->regs[0x1e] = wl >> 2;
0509 data->regs[0x1f] = wl & 3;
0510 }
0511
0512
0513 {
0514 data->regs[0x20] =
0515 data->regs[0x22] = minfo->altout.tvo_params.saturation;
0516 }
0517
0518
0519 data->regs[0x25] = minfo->altout.tvo_params.hue;
0520 return;
0521 }
0522
0523 #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
0524 #define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
0525 static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
0526 int val;
0527
0528
0529 maven_set_reg(c, 0x3E, 0x01);
0530 maven_get_reg(c, 0x82);
0531 maven_set_reg(c, 0x8C, 0x00);
0532 maven_get_reg(c, 0x94);
0533 maven_set_reg(c, 0x94, 0xA2);
0534
0535
0536 maven_set_reg_pair(c, 0x8E, 0x1EFF);
0537 maven_set_reg(c, 0xC6, 0x01);
0538
0539
0540
0541 maven_get_reg(c, 0x06);
0542 maven_set_reg(c, 0x06, 0xF9);
0543
0544
0545
0546
0547
0548 LR(0x00); LR(0x01); LR(0x02); LR(0x03);
0549
0550 LR(0x04);
0551
0552 LR(0x2C);
0553 LR(0x08);
0554 LR(0x0A);
0555 LR(0x09);
0556 LR(0x29);
0557 LRP(0x31);
0558 LRP(0x17);
0559 LR(0x0B);
0560 LR(0x0C);
0561 if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
0562 maven_set_reg(c, 0x35, 0x10);
0563 } else {
0564 maven_set_reg(c, 0x35, 0x0F);
0565 }
0566
0567 LRP(0x10);
0568
0569 LRP(0x0E);
0570 LRP(0x1E);
0571
0572 LR(0x20);
0573 LR(0x22);
0574 LR(0x25);
0575 LR(0x34);
0576 LR(0x33);
0577 LR(0x19);
0578 LR(0x12);
0579 LR(0x3B);
0580 LR(0x13);
0581 LR(0x39);
0582 LR(0x1D);
0583 LR(0x3A);
0584 LR(0x24);
0585 LR(0x14);
0586 LR(0x15);
0587 LR(0x16);
0588 LRP(0x2D);
0589 LRP(0x2F);
0590 LR(0x1A);
0591 LR(0x1B);
0592 LR(0x1C);
0593 LR(0x23);
0594 LR(0x26);
0595 LR(0x28);
0596 LR(0x27);
0597 LR(0x21);
0598 LRP(0x2A);
0599 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
0600 maven_set_reg(c, 0x35, 0x1D);
0601 else
0602 maven_set_reg(c, 0x35, 0x1C);
0603
0604 LRP(0x3C);
0605 LR(0x37);
0606 LR(0x38);
0607 maven_set_reg(c, 0xB3, 0x01);
0608
0609 maven_get_reg(c, 0xB0);
0610 maven_set_reg(c, 0xB0, 0x08);
0611 maven_get_reg(c, 0xB9);
0612 maven_set_reg(c, 0xB9, 0x78);
0613 maven_get_reg(c, 0xBF);
0614 maven_set_reg(c, 0xBF, 0x02);
0615 maven_get_reg(c, 0x94);
0616 maven_set_reg(c, 0x94, 0xB3);
0617
0618 LR(0x80);
0619 LR(0x81);
0620 LR(0x82);
0621
0622 maven_set_reg(c, 0x8C, 0x20);
0623 maven_get_reg(c, 0x8D);
0624 maven_set_reg(c, 0x8D, 0x10);
0625
0626 LR(0x90);
0627 LR(0x91);
0628 LR(0x92);
0629
0630 LRP(0x9A);
0631 LRP(0x9C);
0632 LRP(0x9E);
0633 LRP(0xA0);
0634 LRP(0xA2);
0635 LRP(0xA4);
0636 LRP(0xA6);
0637 LRP(0xA8);
0638 LRP(0x98);
0639 LRP(0xAE);
0640 LRP(0x96);
0641 LRP(0xAA);
0642 LRP(0xAC);
0643
0644 LR(0xBE);
0645 LR(0xC2);
0646
0647 maven_get_reg(c, 0x8D);
0648 maven_set_reg(c, 0x8D, 0x04);
0649
0650 LR(0x20);
0651 LR(0x22);
0652 LR(0x93);
0653 LR(0x20);
0654 LR(0x22);
0655 LR(0x25);
0656 LRP(0x0E);
0657 LRP(0x1E);
0658 LRP(0x0E);
0659 LRP(0x1E);
0660
0661
0662 LR(0x83);
0663 LR(0x84);
0664 LR(0x85);
0665 LR(0x86);
0666 LR(0x87);
0667 LR(0x88);
0668 LR(0x89);
0669 LR(0x8A);
0670 LR(0x8B);
0671
0672 val = maven_get_reg(c, 0x8D);
0673 val &= 0x14;
0674 maven_set_reg(c, 0x8D, val);
0675
0676 LR(0x33);
0677 LR(0x19);
0678 LR(0x12);
0679 LR(0x3B);
0680 LR(0x13);
0681 LR(0x39);
0682 LR(0x1D);
0683 LR(0x3A);
0684 LR(0x24);
0685 LR(0x14);
0686 LR(0x15);
0687 LR(0x16);
0688 LRP(0x2D);
0689 LRP(0x2F);
0690 LR(0x1A);
0691 LR(0x1B);
0692 LR(0x1C);
0693 LR(0x23);
0694 LR(0x26);
0695 LR(0x28);
0696 LR(0x27);
0697 LR(0x21);
0698 LRP(0x2A);
0699 if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
0700 maven_set_reg(c, 0x35, 0x1D);
0701 else
0702 maven_set_reg(c, 0x35, 0x1C);
0703 LRP(0x3C);
0704 LR(0x37);
0705 LR(0x38);
0706
0707 maven_get_reg(c, 0xB0);
0708 LR(0xB0);
0709 LR(0x90);
0710 LR(0xBE);
0711 LR(0xC2);
0712
0713 LRP(0x9A);
0714 LRP(0xA2);
0715 LRP(0x9E);
0716 LRP(0xA6);
0717 LRP(0xAA);
0718 LRP(0xAC);
0719 maven_set_reg(c, 0x3E, 0x00);
0720 maven_set_reg(c, 0x95, 0x20);
0721 }
0722
0723 static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
0724 struct mavenregs* m) {
0725 unsigned int x;
0726 unsigned int err = ~0;
0727
0728
0729 m->regs[0x80] = 0x0F;
0730 m->regs[0x81] = 0x07;
0731 m->regs[0x82] = 0x81;
0732
0733 for (x = 0; x < 8; x++) {
0734 unsigned int c;
0735 unsigned int a, b,
0736 h2;
0737 unsigned int h = ht + 2 + x;
0738
0739 if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
0740 unsigned int diff = h - h2;
0741
0742 if (diff < err) {
0743 err = diff;
0744 m->regs[0x80] = a - 1;
0745 m->regs[0x81] = b - 1;
0746 m->regs[0x82] = c | 0x80;
0747 m->hcorr = h2 - 2;
0748 m->htotal = h - 2;
0749 }
0750 }
0751 }
0752 return err != ~0U;
0753 }
0754
0755 static inline int maven_compute_timming(struct maven_data* md,
0756 struct my_timming* mt,
0757 struct mavenregs* m) {
0758 unsigned int tmpi;
0759 unsigned int a, bv, c;
0760 struct matrox_fb_info *minfo = md->primary_head;
0761
0762 m->mode = minfo->outputs[1].mode;
0763 if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
0764 unsigned int lmargin;
0765 unsigned int umargin;
0766 unsigned int vslen;
0767 unsigned int hcrt;
0768 unsigned int slen;
0769
0770 maven_init_TVdata(md, m);
0771
0772 if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
0773 return -EINVAL;
0774
0775 lmargin = mt->HTotal - mt->HSyncEnd;
0776 slen = mt->HSyncEnd - mt->HSyncStart;
0777 hcrt = mt->HTotal - slen - mt->delay;
0778 umargin = mt->VTotal - mt->VSyncEnd;
0779 vslen = mt->VSyncEnd - mt->VSyncStart;
0780
0781 if (m->hcorr < mt->HTotal)
0782 hcrt += m->hcorr;
0783 if (hcrt > mt->HTotal)
0784 hcrt -= mt->HTotal;
0785 if (hcrt + 2 > mt->HTotal)
0786 hcrt = 0;
0787
0788
0789
0790 m->regs[0x96] = m->hcorr;
0791 m->regs[0x97] = m->hcorr >> 8;
0792
0793 m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
0794
0795 m->regs[0x9A] = lmargin;
0796 m->regs[0x9B] = lmargin >> 8;
0797
0798 m->regs[0x9C] = 0x04;
0799 m->regs[0x9D] = 0x00;
0800
0801 m->regs[0xA0] = m->htotal;
0802 m->regs[0xA1] = m->htotal >> 8;
0803
0804 m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1;
0805 m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
0806
0807 if (md->version == MGATVO_B) {
0808 m->regs[0xA4] = 0x04;
0809 m->regs[0xA5] = 0x00;
0810 } else {
0811 m->regs[0xA4] = 0x01;
0812 m->regs[0xA5] = 0x00;
0813 }
0814
0815 m->regs[0xA6] = 0x00;
0816 m->regs[0xA7] = 0x00;
0817
0818 m->regs[0xA8] = mt->VTotal - 1;
0819 m->regs[0xA9] = (mt->VTotal - 1) >> 8;
0820
0821 m->regs[0xAA] = hcrt;
0822 m->regs[0xAB] = hcrt >> 8;
0823
0824 m->regs[0xAC] = mt->VTotal - 2;
0825 m->regs[0xAD] = (mt->VTotal - 2) >> 8;
0826
0827 m->regs[0xAE] = 0x01;
0828 m->regs[0xAF] = 0x00;
0829 {
0830 int hdec;
0831 int hlen;
0832 unsigned int ibmin = 4 + lmargin + mt->HDisplay;
0833 unsigned int ib;
0834 int i;
0835
0836
0837
0838 if (mt->HTotal)
0839 hdec = 94208 / (mt->HTotal);
0840 else
0841 hdec = 0x81;
0842 if (hdec > 0x81)
0843 hdec = 0x81;
0844 if (hdec < 0x41)
0845 hdec = 0x41;
0846 hdec--;
0847 hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
0848 if (hlen < 0)
0849 hlen = 0;
0850 hlen = hlen >> 8;
0851 if (hlen > 0xFF)
0852 hlen = 0xFF;
0853
0854
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867
0868 i = 1;
0869 do {
0870 ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
0871 i++;
0872 } while (ib < ibmin);
0873 if (ib >= m->htotal + 2) {
0874 ib = ibmin;
0875 }
0876
0877 m->regs[0x90] = hdec;
0878 m->regs[0xC2] = hlen;
0879
0880 m->regs[0x9E] = ib;
0881 m->regs[0x9F] = ib >> 8;
0882 }
0883 {
0884 int vdec;
0885 int vlen;
0886
0887 #define MATROX_USE64BIT_DIVIDE
0888 if (mt->VTotal) {
0889 #ifdef MATROX_USE64BIT_DIVIDE
0890 u64 f1;
0891 u32 a;
0892 u32 b;
0893
0894 a = m->vlines * (m->htotal + 2);
0895 b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
0896
0897 f1 = ((u64)a) << 15;
0898 do_div(f1, b);
0899 vdec = f1;
0900 #else
0901 vdec = m->vlines * 32768 / mt->VTotal;
0902 #endif
0903 } else
0904 vdec = 0x8000;
0905 if (vdec > 0x8000)
0906 vdec = 0x8000;
0907 vlen = (vslen + umargin + mt->VDisplay) * vdec;
0908 vlen = (vlen >> 16) - 146;
0909 if (vlen < 0)
0910 vlen = 0;
0911 if (vlen > 0xFF)
0912 vlen = 0xFF;
0913 vdec--;
0914 m->regs[0x91] = vdec;
0915 m->regs[0x92] = vdec >> 8;
0916 m->regs[0xBE] = vlen;
0917 }
0918 m->regs[0xB0] = 0x08;
0919 return 0;
0920 }
0921
0922 DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
0923 m->regs[0x80] = a;
0924 m->regs[0x81] = bv;
0925 m->regs[0x82] = c | 0x80;
0926
0927 m->regs[0xB3] = 0x01;
0928 m->regs[0x94] = 0xB2;
0929
0930
0931 m->regs[0x96] = mt->HTotal;
0932 m->regs[0x97] = mt->HTotal >> 8;
0933
0934 m->regs[0x98] = 0x00;
0935 m->regs[0x99] = 0x00;
0936
0937 tmpi = mt->HSyncEnd - mt->HSyncStart;
0938 m->regs[0x9A] = tmpi;
0939 m->regs[0x9B] = tmpi >> 8;
0940
0941 tmpi = mt->HTotal - mt->HSyncStart;
0942 m->regs[0x9C] = tmpi;
0943 m->regs[0x9D] = tmpi >> 8;
0944
0945 tmpi += mt->HDisplay;
0946 m->regs[0x9E] = tmpi;
0947 m->regs[0x9F] = tmpi >> 8;
0948
0949 tmpi = mt->HTotal + 1;
0950 m->regs[0xA0] = tmpi;
0951 m->regs[0xA1] = tmpi >> 8;
0952
0953 tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
0954 m->regs[0xA2] = tmpi;
0955 m->regs[0xA3] = tmpi >> 8;
0956
0957 tmpi = mt->VTotal - mt->VSyncStart;
0958 m->regs[0xA4] = tmpi;
0959 m->regs[0xA5] = tmpi >> 8;
0960
0961 tmpi = mt->VTotal - 1;
0962 m->regs[0xA6] = tmpi;
0963 m->regs[0xA7] = tmpi >> 8;
0964
0965 m->regs[0xA8] = tmpi;
0966 m->regs[0xA9] = tmpi >> 8;
0967
0968 tmpi = mt->HTotal - mt->delay;
0969 m->regs[0xAA] = tmpi;
0970 m->regs[0xAB] = tmpi >> 8;
0971
0972 tmpi = mt->VTotal - 2;
0973 m->regs[0xAC] = tmpi;
0974 m->regs[0xAD] = tmpi >> 8;
0975
0976 m->regs[0xAE] = 0x00;
0977 m->regs[0xAF] = 0x00;
0978
0979 m->regs[0xB0] = 0x03;
0980 m->regs[0xB1] = 0xA0;
0981 m->regs[0x8C] = 0x20;
0982 m->regs[0x8D] = 0x04;
0983 m->regs[0xB9] = 0x1A;
0984 m->regs[0xBF] = 0x22;
0985
0986 return 0;
0987 }
0988
0989 static int maven_program_timming(struct maven_data* md,
0990 const struct mavenregs* m) {
0991 struct i2c_client *c = md->client;
0992
0993 if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
0994 LR(0x80);
0995 LR(0x81);
0996 LR(0x82);
0997
0998 LR(0xB3);
0999 LR(0x94);
1000
1001 LRP(0x96);
1002 LRP(0x98);
1003 LRP(0x9A);
1004 LRP(0x9C);
1005 LRP(0x9E);
1006 LRP(0xA0);
1007 LRP(0xA2);
1008 LRP(0xA4);
1009 LRP(0xA6);
1010 LRP(0xA8);
1011 LRP(0xAA);
1012 LRP(0xAC);
1013 LRP(0xAE);
1014
1015 LR(0xB0);
1016 LR(0xB1);
1017 LR(0x8C);
1018 LR(0x8D);
1019 LR(0xB9);
1020 LR(0xBF);
1021 } else {
1022 maven_init_TV(c, m);
1023 }
1024 return 0;
1025 }
1026
1027 static inline int maven_resync(struct maven_data* md) {
1028 struct i2c_client *c = md->client;
1029 maven_set_reg(c, 0x95, 0x20);
1030 return 0;
1031 }
1032
1033 static int maven_get_queryctrl (struct maven_data* md,
1034 struct v4l2_queryctrl *p) {
1035 int i;
1036
1037 i = get_ctrl_id(p->id);
1038 if (i >= 0) {
1039 *p = maven_controls[i].desc;
1040 return 0;
1041 }
1042 if (i == -ENOENT) {
1043 static const struct v4l2_queryctrl disctrl =
1044 { .flags = V4L2_CTRL_FLAG_DISABLED };
1045
1046 i = p->id;
1047 *p = disctrl;
1048 p->id = i;
1049 sprintf(p->name, "Ctrl #%08X", i);
1050 return 0;
1051 }
1052 return -EINVAL;
1053 }
1054
1055 static int maven_set_control (struct maven_data* md,
1056 struct v4l2_control *p) {
1057 int i;
1058
1059 i = get_ctrl_id(p->id);
1060 if (i < 0) return -EINVAL;
1061
1062
1063
1064
1065 if (p->value == *get_ctrl_ptr(md, i)) return 0;
1066
1067
1068
1069
1070 if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
1071 if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
1072
1073
1074
1075
1076 *get_ctrl_ptr(md, i) = p->value;
1077
1078 switch (p->id) {
1079 case V4L2_CID_BRIGHTNESS:
1080 case V4L2_CID_CONTRAST:
1081 {
1082 int blacklevel, whitelevel;
1083 maven_compute_bwlevel(md, &blacklevel, &whitelevel);
1084 blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
1085 whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
1086 maven_set_reg_pair(md->client, 0x0e, blacklevel);
1087 maven_set_reg_pair(md->client, 0x1e, whitelevel);
1088 }
1089 break;
1090 case V4L2_CID_SATURATION:
1091 {
1092 maven_set_reg(md->client, 0x20, p->value);
1093 maven_set_reg(md->client, 0x22, p->value);
1094 }
1095 break;
1096 case V4L2_CID_HUE:
1097 {
1098 maven_set_reg(md->client, 0x25, p->value);
1099 }
1100 break;
1101 case V4L2_CID_GAMMA:
1102 {
1103 const struct maven_gamma* g;
1104 g = maven_compute_gamma(md);
1105 maven_set_reg(md->client, 0x83, g->reg83);
1106 maven_set_reg(md->client, 0x84, g->reg84);
1107 maven_set_reg(md->client, 0x85, g->reg85);
1108 maven_set_reg(md->client, 0x86, g->reg86);
1109 maven_set_reg(md->client, 0x87, g->reg87);
1110 maven_set_reg(md->client, 0x88, g->reg88);
1111 maven_set_reg(md->client, 0x89, g->reg89);
1112 maven_set_reg(md->client, 0x8a, g->reg8a);
1113 maven_set_reg(md->client, 0x8b, g->reg8b);
1114 }
1115 break;
1116 case MATROXFB_CID_TESTOUT:
1117 {
1118 unsigned char val
1119 = maven_get_reg(md->client, 0x8d);
1120 if (p->value) val |= 0x10;
1121 else val &= ~0x10;
1122 maven_set_reg(md->client, 0x8d, val);
1123 }
1124 break;
1125 case MATROXFB_CID_DEFLICKER:
1126 {
1127 maven_set_reg(md->client, 0x93, maven_compute_deflicker(md));
1128 }
1129 break;
1130 }
1131
1132
1133 return 0;
1134 }
1135
1136 static int maven_get_control (struct maven_data* md,
1137 struct v4l2_control *p) {
1138 int i;
1139
1140 i = get_ctrl_id(p->id);
1141 if (i < 0) return -EINVAL;
1142 p->value = *get_ctrl_ptr(md, i);
1143 return 0;
1144 }
1145
1146
1147
1148 static int maven_out_compute(void* md, struct my_timming* mt) {
1149 #define mdinfo ((struct maven_data*)md)
1150 #define minfo (mdinfo->primary_head)
1151 return maven_compute_timming(md, mt, &minfo->hw.maven);
1152 #undef minfo
1153 #undef mdinfo
1154 }
1155
1156 static int maven_out_program(void* md) {
1157 #define mdinfo ((struct maven_data*)md)
1158 #define minfo (mdinfo->primary_head)
1159 return maven_program_timming(md, &minfo->hw.maven);
1160 #undef minfo
1161 #undef mdinfo
1162 }
1163
1164 static int maven_out_start(void* md) {
1165 return maven_resync(md);
1166 }
1167
1168 static int maven_out_verify_mode(void* md, u_int32_t arg) {
1169 switch (arg) {
1170 case MATROXFB_OUTPUT_MODE_PAL:
1171 case MATROXFB_OUTPUT_MODE_NTSC:
1172 case MATROXFB_OUTPUT_MODE_MONITOR:
1173 return 0;
1174 }
1175 return -EINVAL;
1176 }
1177
1178 static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) {
1179 return maven_get_queryctrl(md, p);
1180 }
1181
1182 static int maven_out_get_ctrl(void* md, struct v4l2_control* p) {
1183 return maven_get_control(md, p);
1184 }
1185
1186 static int maven_out_set_ctrl(void* md, struct v4l2_control* p) {
1187 return maven_set_control(md, p);
1188 }
1189
1190 static struct matrox_altout maven_altout = {
1191 .name = "Secondary output",
1192 .compute = maven_out_compute,
1193 .program = maven_out_program,
1194 .start = maven_out_start,
1195 .verifymode = maven_out_verify_mode,
1196 .getqueryctrl = maven_out_get_queryctrl,
1197 .getctrl = maven_out_get_ctrl,
1198 .setctrl = maven_out_set_ctrl,
1199 };
1200
1201 static int maven_init_client(struct i2c_client* clnt) {
1202 struct maven_data* md = i2c_get_clientdata(clnt);
1203 struct matrox_fb_info *minfo = container_of(clnt->adapter,
1204 struct i2c_bit_adapter,
1205 adapter)->minfo;
1206
1207 md->primary_head = minfo;
1208 md->client = clnt;
1209 down_write(&minfo->altout.lock);
1210 minfo->outputs[1].output = &maven_altout;
1211 minfo->outputs[1].src = minfo->outputs[1].default_src;
1212 minfo->outputs[1].data = md;
1213 minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
1214 up_write(&minfo->altout.lock);
1215 if (maven_get_reg(clnt, 0xB2) < 0x14) {
1216 md->version = MGATVO_B;
1217
1218 } else {
1219 md->version = MGATVO_C;
1220 }
1221
1222
1223
1224 {
1225 unsigned int i;
1226
1227 for (i = 0; i < MAVCTRLS; ++i) {
1228 *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
1229 }
1230 }
1231
1232 return 0;
1233 }
1234
1235 static int maven_shutdown_client(struct i2c_client* clnt) {
1236 struct maven_data* md = i2c_get_clientdata(clnt);
1237
1238 if (md->primary_head) {
1239 struct matrox_fb_info *minfo = md->primary_head;
1240
1241 down_write(&minfo->altout.lock);
1242 minfo->outputs[1].src = MATROXFB_SRC_NONE;
1243 minfo->outputs[1].output = NULL;
1244 minfo->outputs[1].data = NULL;
1245 minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
1246 up_write(&minfo->altout.lock);
1247 md->primary_head = NULL;
1248 }
1249 return 0;
1250 }
1251
1252 static int maven_probe(struct i2c_client *client,
1253 const struct i2c_device_id *id)
1254 {
1255 struct i2c_adapter *adapter = client->adapter;
1256 int err = -ENODEV;
1257 struct maven_data* data;
1258
1259 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
1260 I2C_FUNC_SMBUS_BYTE_DATA |
1261 I2C_FUNC_NOSTART |
1262 I2C_FUNC_PROTOCOL_MANGLING))
1263 goto ERROR0;
1264 if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
1265 err = -ENOMEM;
1266 goto ERROR0;
1267 }
1268 i2c_set_clientdata(client, data);
1269 err = maven_init_client(client);
1270 if (err)
1271 goto ERROR4;
1272 return 0;
1273 ERROR4:;
1274 kfree(data);
1275 ERROR0:;
1276 return err;
1277 }
1278
1279 static int maven_remove(struct i2c_client *client)
1280 {
1281 maven_shutdown_client(client);
1282 kfree(i2c_get_clientdata(client));
1283 return 0;
1284 }
1285
1286 static const struct i2c_device_id maven_id[] = {
1287 { "maven", 0 },
1288 { }
1289 };
1290 MODULE_DEVICE_TABLE(i2c, maven_id);
1291
1292 static struct i2c_driver maven_driver={
1293 .driver = {
1294 .name = "maven",
1295 },
1296 .probe = maven_probe,
1297 .remove = maven_remove,
1298 .id_table = maven_id,
1299 };
1300
1301 module_i2c_driver(maven_driver);
1302 MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
1303 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
1304 MODULE_LICENSE("GPL");