Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
0005  *
0006  * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
0007  *
0008  * Portions Copyright (c) 2001 Matrox Graphics Inc.
0009  *
0010  * Version: 1.65 2002/08/14
0011  *
0012  * See matroxfb_base.c for contributors.
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 /* Definition of the various controls */
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 /* Return: positive number: id found
0110            -EINVAL:         id not found, return failure
0111        -ENOENT:         id not found, create fake disabled control */
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 = &reg
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, /* 27027000/60 == 27000000/59.94005994 */
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     /* if h2/post/in/feed have not been assigned, return zero (error) */
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 /*          df |= 0x00; */
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, /* 00: chroma subcarrier */
0375         0x00,
0376         0x00,   /* ? not written */
0377         0x00,   /* modified by code (F9 written...) */
0378         0x00,   /* ? not written */
0379         0x7E,   /* 08 */
0380         0x44,   /* 09 */
0381         0x9C,   /* 0A */
0382         0x2E,   /* 0B */
0383         0x21,   /* 0C */
0384         0x00,   /* ? not written */
0385         0x3F, 0x03, /* 0E-0F */
0386         0x3F, 0x03, /* 10-11 */
0387         0x1A,   /* 12 */
0388         0x2A,   /* 13 */
0389         0x1C, 0x3D, 0x14, /* 14-16 */
0390         0x9C, 0x01, /* 17-18 */
0391         0x00,   /* 19 */
0392         0xFE,   /* 1A */
0393         0x7E,   /* 1B */
0394         0x60,   /* 1C */
0395         0x05,   /* 1D */
0396         0x89, 0x03, /* 1E-1F */
0397         0x72,   /* 20 */
0398         0x07,   /* 21 */
0399         0x72,   /* 22 */
0400         0x00,   /* 23 */
0401         0x00,   /* 24 */
0402         0x00,   /* 25 */
0403         0x08,   /* 26 */
0404         0x04,   /* 27 */
0405         0x00,   /* 28 */
0406         0x1A,   /* 29 */
0407         0x55, 0x01, /* 2A-2B */
0408         0x26,   /* 2C */
0409         0x07, 0x7E, /* 2D-2E */
0410         0x02, 0x54, /* 2F-30 */
0411         0xB0, 0x00, /* 31-32 */
0412         0x14,   /* 33 */
0413         0x49,   /* 34 */
0414         0x00,   /* 35 written multiple times */
0415         0x00,   /* 36 not written */
0416         0xA3,   /* 37 */
0417         0xC8,   /* 38 */
0418         0x22,   /* 39 */
0419         0x02,   /* 3A */
0420         0x22,   /* 3B */
0421         0x3F, 0x03, /* 3C-3D */
0422         0x00,   /* 3E written multiple times */
0423         0x00,   /* 3F not written */
0424     }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
0425     static struct mavenregs ntscregs = { {
0426         0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */
0427         0x00,
0428         0x00,   /* ? not written */
0429         0x00,   /* modified by code (F9 written...) */
0430         0x00,   /* ? not written */
0431         0x7E,   /* 08 */
0432         0x43,   /* 09 */
0433         0x7E,   /* 0A */
0434         0x3D,   /* 0B */
0435         0x00,   /* 0C */
0436         0x00,   /* ? not written */
0437         0x41, 0x00, /* 0E-0F */
0438         0x3C, 0x00, /* 10-11 */
0439         0x17,   /* 12 */
0440         0x21,   /* 13 */
0441         0x1B, 0x1B, 0x24, /* 14-16 */
0442         0x83, 0x01, /* 17-18 */
0443         0x00,   /* 19 */
0444         0x0F,   /* 1A */
0445         0x0F,   /* 1B */
0446         0x60,   /* 1C */
0447         0x05,   /* 1D */
0448         0x89, 0x02, /* 1E-1F */
0449         0x5F,   /* 20 */
0450         0x04,   /* 21 */
0451         0x5F,   /* 22 */
0452         0x01,   /* 23 */
0453         0x02,   /* 24 */
0454         0x00,   /* 25 */
0455         0x0A,   /* 26 */
0456         0x05,   /* 27 */
0457         0x00,   /* 28 */
0458         0x10,   /* 29 */
0459         0xFF, 0x03, /* 2A-2B */
0460         0x24,   /* 2C */
0461         0x0F, 0x78, /* 2D-2E */
0462         0x00, 0x00, /* 2F-30 */
0463         0xB2, 0x04, /* 31-32 */
0464         0x14,   /* 33 */
0465         0x02,   /* 34 */
0466         0x00,   /* 35 written multiple times */
0467         0x00,   /* 36 not written */
0468         0xA3,   /* 37 */
0469         0xC8,   /* 38 */
0470         0x15,   /* 39 */
0471         0x05,   /* 3A */
0472         0x3B,   /* 3B */
0473         0x3C, 0x00, /* 3C-3D */
0474         0x00,   /* 3E written multiple times */
0475         0x00,   /* never written */
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     /* Set deflicker */
0485     data->regs[0x93] = maven_compute_deflicker(md);
0486  
0487     /* set gamma */
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     /* Set contrast / brightness */
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     /* Set saturation */
0513     {
0514         data->regs[0x20] =
0515         data->regs[0x22] = minfo->altout.tvo_params.saturation;
0516     }
0517  
0518     /* Set HUE */
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); /* fetch oscillator state? */
0531     maven_set_reg(c, 0x8C, 0x00);
0532     maven_get_reg(c, 0x94); /* get 0x82 */
0533     maven_set_reg(c, 0x94, 0xA2);
0534     /* xmiscctrl */
0535 
0536     maven_set_reg_pair(c, 0x8E, 0x1EFF);
0537     maven_set_reg(c, 0xC6, 0x01);
0538 
0539     /* removed code... */
0540 
0541     maven_get_reg(c, 0x06);
0542     maven_set_reg(c, 0x06, 0xF9);   /* or read |= 0xF0 ? */
0543 
0544     /* removed code here... */
0545 
0546     /* real code begins here? */
0547     /* chroma subcarrier */
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);   /* saturation #1 */
0573     LR(0x22);   /* saturation #2 */
0574     LR(0x25);   /* hue */
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); /* read 0x80 */
0610     maven_set_reg(c, 0xB0, 0x08);   /* ugh... */
0611     maven_get_reg(c, 0xB9); /* read 0x7C */
0612     maven_set_reg(c, 0xB9, 0x78);
0613     maven_get_reg(c, 0xBF); /* read 0x00 */
0614     maven_set_reg(c, 0xBF, 0x02);
0615     maven_get_reg(c, 0x94); /* read 0x82 */
0616     maven_set_reg(c, 0x94, 0xB3);
0617 
0618     LR(0x80); /* 04 1A 91 or 05 21 91 */
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); /* 4D 50 52 or 4E 05 45 */
0627     LR(0x91);
0628     LR(0x92);
0629 
0630     LRP(0x9A); /* 0049 or 004F */
0631     LRP(0x9C); /* 0004 or 0004 */
0632     LRP(0x9E); /* 0458 or 045E */
0633     LRP(0xA0); /* 05DA or 051B */
0634     LRP(0xA2); /* 00CC or 00CF */
0635     LRP(0xA4); /* 007D or 007F */
0636     LRP(0xA6); /* 007C or 007E */
0637     LRP(0xA8); /* 03CB or 03CE */
0638     LRP(0x98); /* 0000 or 0000 */
0639     LRP(0xAE); /* 0044 or 003A */
0640     LRP(0x96); /* 05DA or 051B */
0641     LRP(0xAA); /* 04BC or 046A */
0642     LRP(0xAC); /* 004D or 004E */
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);   /* saturation #1 */
0651     LR(0x22);   /* saturation #2 */
0652     LR(0x93);   /* whoops */
0653     LR(0x20);   /* oh, saturation #1 again */
0654     LR(0x22);   /* oh, saturation #2 again */
0655     LR(0x25);   /* hue */
0656     LRP(0x0E);
0657     LRP(0x1E);
0658     LRP(0x0E);  /* problems with memory? */
0659     LRP(0x1E);  /* yes, matrox must have problems in memory area... */
0660 
0661     /* load gamma correction stuff */
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;            /* 0x10 or anything ored with it */
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);   /* output mode */
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     /* 1:1 */
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;   /* or issue warning? */
0787 
0788         /* last (first? middle?) line in picture can have different length */
0789         /* hlen - 2 */
0790         m->regs[0x96] = m->hcorr;
0791         m->regs[0x97] = m->hcorr >> 8;
0792         /* ... */
0793         m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
0794         /* hblanking end */
0795         m->regs[0x9A] = lmargin;    /* 100% */
0796         m->regs[0x9B] = lmargin >> 8;   /* 100% */
0797         /* who knows */
0798         m->regs[0x9C] = 0x04;
0799         m->regs[0x9D] = 0x00;
0800         /* htotal - 2 */
0801         m->regs[0xA0] = m->htotal;
0802         m->regs[0xA1] = m->htotal >> 8;
0803         /* vblanking end */
0804         m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1;    /* stop vblanking */
0805         m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
0806         /* something end... [A6]+1..[A8] */
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         /* something start... 0..[A4]-1 */
0815         m->regs[0xA6] = 0x00;
0816         m->regs[0xA7] = 0x00;
0817         /* vertical line count - 1 */
0818         m->regs[0xA8] = mt->VTotal - 1;
0819         m->regs[0xA9] = (mt->VTotal - 1) >> 8;
0820         /* horizontal vidrst pos */
0821         m->regs[0xAA] = hcrt;       /* 0 <= hcrt <= htotal - 2 */
0822         m->regs[0xAB] = hcrt >> 8;
0823         /* vertical vidrst pos */
0824         m->regs[0xAC] = mt->VTotal - 2;
0825         m->regs[0xAD] = (mt->VTotal - 2) >> 8;
0826         /* moves picture up/down and so on... */
0827         m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
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             /* Verify! */
0837             /* Where 94208 came from? */
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             /* Now we have to compute input buffer length.
0854                If you want any picture, it must be between
0855                  4 + lmargin + xres
0856                and
0857                  94208 / hdec
0858                If you want perfect picture even on the top
0859                of screen, it must be also
0860                  0x3C0000 * i / hdec + Q - R / hdec
0861                where
0862                     R      Qmin   Qmax
0863                  0x07000   0x5AE  0x5BF
0864                  0x08000   0x5CF  0x5FF
0865                  0x0C000   0x653  0x67F
0866                  0x10000   0x6F8  0x6FF
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;   /* < 0x40 || > 0x80 is bad... 0x80 is questionable */
0878             m->regs[0xC2] = hlen;
0879             /* 'valid' input line length */
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;    /* *32768 */
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; /* FIXME: 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;   /* output: SVideo/Composite */
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     /* htotal... */
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     /* hsync len */
0937     tmpi = mt->HSyncEnd - mt->HSyncStart;
0938     m->regs[0x9A] = tmpi;
0939     m->regs[0x9B] = tmpi >> 8;
0940     /* hblank end */
0941     tmpi = mt->HTotal - mt->HSyncStart;
0942     m->regs[0x9C] = tmpi;
0943     m->regs[0x9D] = tmpi >> 8;
0944     /* hblank start */
0945     tmpi += mt->HDisplay;
0946     m->regs[0x9E] = tmpi;
0947     m->regs[0x9F] = tmpi >> 8;
0948     /* htotal + 1 */
0949     tmpi = mt->HTotal + 1;
0950     m->regs[0xA0] = tmpi;
0951     m->regs[0xA1] = tmpi >> 8;
0952     /* vsync?! */
0953     tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
0954     m->regs[0xA2] = tmpi;
0955     m->regs[0xA3] = tmpi >> 8;
0956     /* ignored? */
0957     tmpi = mt->VTotal - mt->VSyncStart;
0958     m->regs[0xA4] = tmpi;
0959     m->regs[0xA5] = tmpi >> 8;
0960     /* ignored? */
0961     tmpi = mt->VTotal - 1;
0962     m->regs[0xA6] = tmpi;
0963     m->regs[0xA7] = tmpi >> 8;
0964     /* vtotal - 1 */
0965     m->regs[0xA8] = tmpi;
0966     m->regs[0xA9] = tmpi >> 8;
0967     /* hor vidrst */
0968     tmpi = mt->HTotal - mt->delay;
0969     m->regs[0xAA] = tmpi;
0970     m->regs[0xAB] = tmpi >> 8;
0971     /* vert vidrst */
0972     tmpi = mt->VTotal - 2;
0973     m->regs[0xAC] = tmpi;
0974     m->regs[0xAD] = tmpi >> 8;
0975     /* ignored? */
0976     m->regs[0xAE] = 0x00;
0977     m->regs[0xAF] = 0x00;
0978 
0979     m->regs[0xB0] = 0x03;   /* output: monitor */
0980     m->regs[0xB1] = 0xA0;   /* ??? */
0981     m->regs[0x8C] = 0x20;   /* must be set... */
0982     m->regs[0x8D] = 0x04;   /* defaults to 0x10: test signal */
0983     m->regs[0xB9] = 0x1A;   /* defaults to 0x2C: too bright */
0984     m->regs[0xBF] = 0x22;   /* makes picture stable */
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);   /* output: monitor */
1016         LR(0xB1);   /* ??? */
1017         LR(0x8C);   /* must be set... */
1018         LR(0x8D);   /* defaults to 0x10: test signal */
1019         LR(0xB9);   /* defaults to 0x2C: too bright */
1020         LR(0xBF);   /* makes picture stable */
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);   /* start whole thing */
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      * Check if changed.
1064      */
1065     if (p->value == *get_ctrl_ptr(md, i)) return 0;
1066 
1067     /*
1068      * Check limits.
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      * Store new value.
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         /* Tweak some things for this old chip */
1218     } else {
1219         md->version = MGATVO_C;
1220     }
1221     /*
1222      * Set all parameters to its initial values.
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");