162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Portions Copyright (c) 2001 Matrox Graphics Inc.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Version: 1.65 2002/08/14
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * See matroxfb_base.c for contributors.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "matroxfb_maven.h"
1762306a36Sopenharmony_ci#include "matroxfb_misc.h"
1862306a36Sopenharmony_ci#include "matroxfb_DAC1064.h"
1962306a36Sopenharmony_ci#include <linux/i2c.h>
2062306a36Sopenharmony_ci#include <linux/matroxfb.h>
2162306a36Sopenharmony_ci#include <linux/slab.h>
2262306a36Sopenharmony_ci#include <asm/div64.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define MGATVO_B	1
2562306a36Sopenharmony_ci#define MGATVO_C	2
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic const struct maven_gamma {
2862306a36Sopenharmony_ci  unsigned char reg83;
2962306a36Sopenharmony_ci  unsigned char reg84;
3062306a36Sopenharmony_ci  unsigned char reg85;
3162306a36Sopenharmony_ci  unsigned char reg86;
3262306a36Sopenharmony_ci  unsigned char reg87;
3362306a36Sopenharmony_ci  unsigned char reg88;
3462306a36Sopenharmony_ci  unsigned char reg89;
3562306a36Sopenharmony_ci  unsigned char reg8a;
3662306a36Sopenharmony_ci  unsigned char reg8b;
3762306a36Sopenharmony_ci} maven_gamma[] = {
3862306a36Sopenharmony_ci  { 131, 57, 223, 15, 117, 212, 251, 91, 156},
3962306a36Sopenharmony_ci  { 133, 61, 128, 63, 180, 147, 195, 100, 180},
4062306a36Sopenharmony_ci  { 131, 19, 63, 31, 50, 66, 171, 64, 176},
4162306a36Sopenharmony_ci  { 0, 0, 0, 31, 16, 16, 16, 100, 200},
4262306a36Sopenharmony_ci  { 8, 23, 47, 73, 147, 244, 220, 80, 195},
4362306a36Sopenharmony_ci  { 22, 43, 64, 80, 147, 115, 58, 85, 168},
4462306a36Sopenharmony_ci  { 34, 60, 80, 214, 147, 212, 188, 85, 167},
4562306a36Sopenharmony_ci  { 45, 77, 96, 216, 147, 99, 91, 85, 159},
4662306a36Sopenharmony_ci  { 56, 76, 112, 107, 147, 212, 148, 64, 144},
4762306a36Sopenharmony_ci  { 65, 91, 128, 137, 147, 196, 17, 69, 148},
4862306a36Sopenharmony_ci  { 72, 104, 136, 138, 147, 180, 245, 73, 147},
4962306a36Sopenharmony_ci  { 87, 116, 143, 126, 16, 83, 229, 77, 144},
5062306a36Sopenharmony_ci  { 95, 119, 152, 254, 244, 83, 221, 77, 151},
5162306a36Sopenharmony_ci  { 100, 129, 159, 156, 244, 148, 197, 77, 160},
5262306a36Sopenharmony_ci  { 105, 141, 167, 247, 244, 132, 181, 84, 166},
5362306a36Sopenharmony_ci  { 105, 147, 168, 247, 244, 245, 181, 90, 170},
5462306a36Sopenharmony_ci  { 120, 153, 175, 248, 212, 229, 165, 90, 180},
5562306a36Sopenharmony_ci  { 119, 156, 176, 248, 244, 229, 84, 74, 160},
5662306a36Sopenharmony_ci  { 119, 158, 183, 248, 244, 229, 149, 78, 165}
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* Definition of the various controls */
6062306a36Sopenharmony_cistruct mctl {
6162306a36Sopenharmony_ci	struct v4l2_queryctrl desc;
6262306a36Sopenharmony_ci	size_t control;
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define BLMIN	0x0FF
6662306a36Sopenharmony_ci#define WLMAX	0x3FF
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic const struct mctl maven_controls[] =
6962306a36Sopenharmony_ci{	{ { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
7062306a36Sopenharmony_ci	  "brightness",
7162306a36Sopenharmony_ci	  0, WLMAX - BLMIN, 1, 379 - BLMIN,
7262306a36Sopenharmony_ci	  0,
7362306a36Sopenharmony_ci	}, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
7462306a36Sopenharmony_ci	{ { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
7562306a36Sopenharmony_ci	  "contrast",
7662306a36Sopenharmony_ci	  0, 1023, 1, 127,
7762306a36Sopenharmony_ci	  0,
7862306a36Sopenharmony_ci	}, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
7962306a36Sopenharmony_ci	{ { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
8062306a36Sopenharmony_ci	  "saturation",
8162306a36Sopenharmony_ci	  0, 255, 1, 155,
8262306a36Sopenharmony_ci	  0,
8362306a36Sopenharmony_ci	}, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
8462306a36Sopenharmony_ci	{ { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
8562306a36Sopenharmony_ci	  "hue",
8662306a36Sopenharmony_ci	  0, 255, 1, 0,
8762306a36Sopenharmony_ci	  0,
8862306a36Sopenharmony_ci	}, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
8962306a36Sopenharmony_ci	{ { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER,
9062306a36Sopenharmony_ci	  "gamma",
9162306a36Sopenharmony_ci	  0, ARRAY_SIZE(maven_gamma) - 1, 1, 3,
9262306a36Sopenharmony_ci	  0,
9362306a36Sopenharmony_ci	}, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
9462306a36Sopenharmony_ci	{ { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN,
9562306a36Sopenharmony_ci	  "test output",
9662306a36Sopenharmony_ci	  0, 1, 1, 0,
9762306a36Sopenharmony_ci	  0,
9862306a36Sopenharmony_ci	}, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
9962306a36Sopenharmony_ci	{ { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER,
10062306a36Sopenharmony_ci	  "deflicker mode",
10162306a36Sopenharmony_ci	  0, 2, 1, 0,
10262306a36Sopenharmony_ci	  0,
10362306a36Sopenharmony_ci	}, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define MAVCTRLS ARRAY_SIZE(maven_controls)
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* Return: positive number: id found
11062306a36Sopenharmony_ci           -EINVAL:         id not found, return failure
11162306a36Sopenharmony_ci	   -ENOENT:         id not found, create fake disabled control */
11262306a36Sopenharmony_cistatic int get_ctrl_id(__u32 v4l2_id) {
11362306a36Sopenharmony_ci	int i;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	for (i = 0; i < MAVCTRLS; i++) {
11662306a36Sopenharmony_ci		if (v4l2_id < maven_controls[i].desc.id) {
11762306a36Sopenharmony_ci			if (maven_controls[i].desc.id == 0x08000000) {
11862306a36Sopenharmony_ci				return -EINVAL;
11962306a36Sopenharmony_ci			}
12062306a36Sopenharmony_ci			return -ENOENT;
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci		if (v4l2_id == maven_controls[i].desc.id) {
12362306a36Sopenharmony_ci			return i;
12462306a36Sopenharmony_ci		}
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci	return -EINVAL;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistruct maven_data {
13062306a36Sopenharmony_ci	struct matrox_fb_info*		primary_head;
13162306a36Sopenharmony_ci	struct i2c_client		*client;
13262306a36Sopenharmony_ci	int				version;
13362306a36Sopenharmony_ci};
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic int* get_ctrl_ptr(struct maven_data* md, int idx) {
13662306a36Sopenharmony_ci	return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic int maven_get_reg(struct i2c_client* c, char reg) {
14062306a36Sopenharmony_ci	char dst;
14162306a36Sopenharmony_ci	struct i2c_msg msgs[] = {
14262306a36Sopenharmony_ci		{
14362306a36Sopenharmony_ci			.addr = c->addr,
14462306a36Sopenharmony_ci			.flags = I2C_M_REV_DIR_ADDR,
14562306a36Sopenharmony_ci			.len = sizeof(reg),
14662306a36Sopenharmony_ci			.buf = &reg
14762306a36Sopenharmony_ci		},
14862306a36Sopenharmony_ci		{
14962306a36Sopenharmony_ci			.addr = c->addr,
15062306a36Sopenharmony_ci			.flags = I2C_M_RD | I2C_M_NOSTART,
15162306a36Sopenharmony_ci			.len = sizeof(dst),
15262306a36Sopenharmony_ci			.buf = &dst
15362306a36Sopenharmony_ci		}
15462306a36Sopenharmony_ci	};
15562306a36Sopenharmony_ci	s32 err;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	err = i2c_transfer(c->adapter, msgs, 2);
15862306a36Sopenharmony_ci	if (err < 0)
15962306a36Sopenharmony_ci		printk(KERN_INFO "ReadReg(%d) failed\n", reg);
16062306a36Sopenharmony_ci	return dst & 0xFF;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int maven_set_reg(struct i2c_client* c, int reg, int val) {
16462306a36Sopenharmony_ci	s32 err;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	err = i2c_smbus_write_byte_data(c, reg, val);
16762306a36Sopenharmony_ci	if (err)
16862306a36Sopenharmony_ci		printk(KERN_INFO "WriteReg(%d) failed\n", reg);
16962306a36Sopenharmony_ci	return err;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic int maven_set_reg_pair(struct i2c_client* c, int reg, int val) {
17362306a36Sopenharmony_ci	s32 err;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	err = i2c_smbus_write_word_data(c, reg, val);
17662306a36Sopenharmony_ci	if (err)
17762306a36Sopenharmony_ci		printk(KERN_INFO "WriteRegPair(%d) failed\n", reg);
17862306a36Sopenharmony_ci	return err;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic const struct matrox_pll_features maven_pll = {
18262306a36Sopenharmony_ci	50000,
18362306a36Sopenharmony_ci	27000,
18462306a36Sopenharmony_ci	4, 127,
18562306a36Sopenharmony_ci	2, 31,
18662306a36Sopenharmony_ci	3
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistruct matrox_pll_features2 {
19062306a36Sopenharmony_ci	unsigned int	vco_freq_min;
19162306a36Sopenharmony_ci	unsigned int	vco_freq_max;
19262306a36Sopenharmony_ci	unsigned int	feed_div_min;
19362306a36Sopenharmony_ci	unsigned int	feed_div_max;
19462306a36Sopenharmony_ci	unsigned int	in_div_min;
19562306a36Sopenharmony_ci	unsigned int	in_div_max;
19662306a36Sopenharmony_ci	unsigned int	post_shift_max;
19762306a36Sopenharmony_ci};
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistruct matrox_pll_ctl {
20062306a36Sopenharmony_ci	unsigned int	ref_freq;
20162306a36Sopenharmony_ci	unsigned int	den;
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic const struct matrox_pll_features2 maven1000_pll = {
20562306a36Sopenharmony_ci	.vco_freq_min = 50000000,
20662306a36Sopenharmony_ci	.vco_freq_max = 300000000,
20762306a36Sopenharmony_ci	.feed_div_min = 5,
20862306a36Sopenharmony_ci	.feed_div_max = 128,
20962306a36Sopenharmony_ci	.in_div_min = 3,
21062306a36Sopenharmony_ci	.in_div_max = 32,
21162306a36Sopenharmony_ci	.post_shift_max = 3
21262306a36Sopenharmony_ci};
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic const struct matrox_pll_ctl maven_PAL = {
21562306a36Sopenharmony_ci	.ref_freq = 540000,
21662306a36Sopenharmony_ci	.den = 50
21762306a36Sopenharmony_ci};
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic const struct matrox_pll_ctl maven_NTSC = {
22062306a36Sopenharmony_ci	.ref_freq = 450450,	/* 27027000/60 == 27000000/59.94005994 */
22162306a36Sopenharmony_ci	.den = 60
22262306a36Sopenharmony_ci};
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
22562306a36Sopenharmony_ci		const struct matrox_pll_ctl* ctl,
22662306a36Sopenharmony_ci		unsigned int htotal, unsigned int vtotal,
22762306a36Sopenharmony_ci		unsigned int* in, unsigned int* feed, unsigned int* post,
22862306a36Sopenharmony_ci		unsigned int* h2) {
22962306a36Sopenharmony_ci	unsigned int besth2 = 0;
23062306a36Sopenharmony_ci	unsigned int fxtal = ctl->ref_freq;
23162306a36Sopenharmony_ci	unsigned int fmin = pll->vco_freq_min / ctl->den;
23262306a36Sopenharmony_ci	unsigned int fwant;
23362306a36Sopenharmony_ci	unsigned int p;
23462306a36Sopenharmony_ci	unsigned int scrlen;
23562306a36Sopenharmony_ci	unsigned int fmax;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	DBG(__func__)
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	scrlen = htotal * (vtotal - 1);
24062306a36Sopenharmony_ci	fwant = htotal * vtotal;
24162306a36Sopenharmony_ci	fmax = pll->vco_freq_max / ctl->den;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
24462306a36Sopenharmony_ci		fwant, fxtal, htotal, vtotal, fmax);
24562306a36Sopenharmony_ci	for (p = 1; p <= pll->post_shift_max; p++) {
24662306a36Sopenharmony_ci		if (fwant * 2 > fmax)
24762306a36Sopenharmony_ci			break;
24862306a36Sopenharmony_ci		fwant *= 2;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci	if (fwant > fmax)
25162306a36Sopenharmony_ci		return 0;
25262306a36Sopenharmony_ci	for (; p-- > 0; fwant >>= 1) {
25362306a36Sopenharmony_ci		unsigned int m;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		if (fwant < fmin) break;
25662306a36Sopenharmony_ci		for (m = pll->in_div_min; m <= pll->in_div_max; m++) {
25762306a36Sopenharmony_ci			unsigned int n;
25862306a36Sopenharmony_ci			unsigned int dvd;
25962306a36Sopenharmony_ci			unsigned int ln;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci			n = (fwant * m) / fxtal;
26262306a36Sopenharmony_ci			if (n < pll->feed_div_min)
26362306a36Sopenharmony_ci				continue;
26462306a36Sopenharmony_ci			if (n > pll->feed_div_max)
26562306a36Sopenharmony_ci				break;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci			ln = fxtal * n;
26862306a36Sopenharmony_ci			dvd = m << p;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci			if (ln % dvd)
27162306a36Sopenharmony_ci				continue;
27262306a36Sopenharmony_ci			ln = ln / dvd;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci			if (ln < scrlen + 2)
27562306a36Sopenharmony_ci				continue;
27662306a36Sopenharmony_ci			ln = ln - scrlen;
27762306a36Sopenharmony_ci			if (ln > htotal)
27862306a36Sopenharmony_ci				continue;
27962306a36Sopenharmony_ci			dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
28062306a36Sopenharmony_ci			if (ln > besth2) {
28162306a36Sopenharmony_ci				dprintk(KERN_DEBUG "Better...\n");
28262306a36Sopenharmony_ci				*h2 = besth2 = ln;
28362306a36Sopenharmony_ci				*post = p;
28462306a36Sopenharmony_ci				*in = m;
28562306a36Sopenharmony_ci				*feed = n;
28662306a36Sopenharmony_ci			}
28762306a36Sopenharmony_ci		}
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	/* if h2/post/in/feed have not been assigned, return zero (error) */
29162306a36Sopenharmony_ci	if (besth2 < 2)
29262306a36Sopenharmony_ci		return 0;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
29562306a36Sopenharmony_ci	return fxtal * (*feed) / (*in) * ctl->den;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic int matroxfb_mavenclock(const struct matrox_pll_ctl *ctl,
29962306a36Sopenharmony_ci		unsigned int htotal, unsigned int vtotal,
30062306a36Sopenharmony_ci		unsigned int* in, unsigned int* feed, unsigned int* post,
30162306a36Sopenharmony_ci		unsigned int* htotal2) {
30262306a36Sopenharmony_ci	unsigned int fvco;
30362306a36Sopenharmony_ci	unsigned int p;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
30662306a36Sopenharmony_ci	if (!fvco)
30762306a36Sopenharmony_ci		return -EINVAL;
30862306a36Sopenharmony_ci	p = (1 << p) - 1;
30962306a36Sopenharmony_ci	if (fvco <= 100000000)
31062306a36Sopenharmony_ci		;
31162306a36Sopenharmony_ci	else if (fvco <= 140000000)
31262306a36Sopenharmony_ci		p |= 0x08;
31362306a36Sopenharmony_ci	else if (fvco <= 180000000)
31462306a36Sopenharmony_ci		p |= 0x10;
31562306a36Sopenharmony_ci	else
31662306a36Sopenharmony_ci		p |= 0x18;
31762306a36Sopenharmony_ci	*post = p;
31862306a36Sopenharmony_ci	return 0;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic void DAC1064_calcclock(unsigned int freq, unsigned int fmax,
32262306a36Sopenharmony_ci		unsigned int* in, unsigned int* feed, unsigned int* post) {
32362306a36Sopenharmony_ci	unsigned int fvco;
32462306a36Sopenharmony_ci	unsigned int p;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p);
32762306a36Sopenharmony_ci	p = (1 << p) - 1;
32862306a36Sopenharmony_ci	if (fvco <= 100000)
32962306a36Sopenharmony_ci		;
33062306a36Sopenharmony_ci	else if (fvco <= 140000)
33162306a36Sopenharmony_ci		p |= 0x08;
33262306a36Sopenharmony_ci	else if (fvco <= 180000)
33362306a36Sopenharmony_ci		p |= 0x10;
33462306a36Sopenharmony_ci	else
33562306a36Sopenharmony_ci		p |= 0x18;
33662306a36Sopenharmony_ci	*post = p;
33762306a36Sopenharmony_ci	return;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic unsigned char maven_compute_deflicker (const struct maven_data* md) {
34162306a36Sopenharmony_ci	unsigned char df;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	df = (md->version == MGATVO_B?0x40:0x00);
34462306a36Sopenharmony_ci	switch (md->primary_head->altout.tvo_params.deflicker) {
34562306a36Sopenharmony_ci		case 0:
34662306a36Sopenharmony_ci/*			df |= 0x00; */
34762306a36Sopenharmony_ci			break;
34862306a36Sopenharmony_ci		case 1:
34962306a36Sopenharmony_ci			df |= 0xB1;
35062306a36Sopenharmony_ci			break;
35162306a36Sopenharmony_ci		case 2:
35262306a36Sopenharmony_ci			df |= 0xA2;
35362306a36Sopenharmony_ci			break;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci	return df;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic void maven_compute_bwlevel (const struct maven_data* md,
35962306a36Sopenharmony_ci				   int *bl, int *wl) {
36062306a36Sopenharmony_ci	const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
36162306a36Sopenharmony_ci	const int c = md->primary_head->altout.tvo_params.contrast;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	*bl = max(b - c, BLMIN);
36462306a36Sopenharmony_ci	*wl = min(b + c, WLMAX);
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
36862306a36Sopenharmony_ci 	return maven_gamma + md->primary_head->altout.tvo_params.gamma;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
37362306a36Sopenharmony_ci	static struct mavenregs palregs = { {
37462306a36Sopenharmony_ci		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
37562306a36Sopenharmony_ci		0x00,
37662306a36Sopenharmony_ci		0x00,	/* ? not written */
37762306a36Sopenharmony_ci		0x00,	/* modified by code (F9 written...) */
37862306a36Sopenharmony_ci		0x00,	/* ? not written */
37962306a36Sopenharmony_ci		0x7E,	/* 08 */
38062306a36Sopenharmony_ci		0x44,	/* 09 */
38162306a36Sopenharmony_ci		0x9C,	/* 0A */
38262306a36Sopenharmony_ci		0x2E,	/* 0B */
38362306a36Sopenharmony_ci		0x21,	/* 0C */
38462306a36Sopenharmony_ci		0x00,	/* ? not written */
38562306a36Sopenharmony_ci		0x3F, 0x03, /* 0E-0F */
38662306a36Sopenharmony_ci		0x3F, 0x03, /* 10-11 */
38762306a36Sopenharmony_ci		0x1A,	/* 12 */
38862306a36Sopenharmony_ci		0x2A,	/* 13 */
38962306a36Sopenharmony_ci		0x1C, 0x3D, 0x14, /* 14-16 */
39062306a36Sopenharmony_ci		0x9C, 0x01, /* 17-18 */
39162306a36Sopenharmony_ci		0x00,	/* 19 */
39262306a36Sopenharmony_ci		0xFE,	/* 1A */
39362306a36Sopenharmony_ci		0x7E,	/* 1B */
39462306a36Sopenharmony_ci		0x60,	/* 1C */
39562306a36Sopenharmony_ci		0x05,	/* 1D */
39662306a36Sopenharmony_ci		0x89, 0x03, /* 1E-1F */
39762306a36Sopenharmony_ci		0x72,	/* 20 */
39862306a36Sopenharmony_ci		0x07,	/* 21 */
39962306a36Sopenharmony_ci		0x72,	/* 22 */
40062306a36Sopenharmony_ci		0x00,	/* 23 */
40162306a36Sopenharmony_ci		0x00,	/* 24 */
40262306a36Sopenharmony_ci		0x00,	/* 25 */
40362306a36Sopenharmony_ci		0x08,	/* 26 */
40462306a36Sopenharmony_ci		0x04,	/* 27 */
40562306a36Sopenharmony_ci		0x00,	/* 28 */
40662306a36Sopenharmony_ci		0x1A,	/* 29 */
40762306a36Sopenharmony_ci		0x55, 0x01, /* 2A-2B */
40862306a36Sopenharmony_ci		0x26,	/* 2C */
40962306a36Sopenharmony_ci		0x07, 0x7E, /* 2D-2E */
41062306a36Sopenharmony_ci		0x02, 0x54, /* 2F-30 */
41162306a36Sopenharmony_ci		0xB0, 0x00, /* 31-32 */
41262306a36Sopenharmony_ci		0x14,	/* 33 */
41362306a36Sopenharmony_ci		0x49,	/* 34 */
41462306a36Sopenharmony_ci		0x00,	/* 35 written multiple times */
41562306a36Sopenharmony_ci		0x00,	/* 36 not written */
41662306a36Sopenharmony_ci		0xA3,	/* 37 */
41762306a36Sopenharmony_ci		0xC8,	/* 38 */
41862306a36Sopenharmony_ci		0x22,	/* 39 */
41962306a36Sopenharmony_ci		0x02,	/* 3A */
42062306a36Sopenharmony_ci		0x22,	/* 3B */
42162306a36Sopenharmony_ci		0x3F, 0x03, /* 3C-3D */
42262306a36Sopenharmony_ci		0x00,	/* 3E written multiple times */
42362306a36Sopenharmony_ci		0x00,	/* 3F not written */
42462306a36Sopenharmony_ci	}, MATROXFB_OUTPUT_MODE_PAL, 625, 50 };
42562306a36Sopenharmony_ci	static struct mavenregs ntscregs = { {
42662306a36Sopenharmony_ci		0x21, 0xF0, 0x7C, 0x1F,	/* 00: chroma subcarrier */
42762306a36Sopenharmony_ci		0x00,
42862306a36Sopenharmony_ci		0x00,	/* ? not written */
42962306a36Sopenharmony_ci		0x00,	/* modified by code (F9 written...) */
43062306a36Sopenharmony_ci		0x00,	/* ? not written */
43162306a36Sopenharmony_ci		0x7E,	/* 08 */
43262306a36Sopenharmony_ci		0x43,	/* 09 */
43362306a36Sopenharmony_ci		0x7E,	/* 0A */
43462306a36Sopenharmony_ci		0x3D,	/* 0B */
43562306a36Sopenharmony_ci		0x00,	/* 0C */
43662306a36Sopenharmony_ci		0x00,	/* ? not written */
43762306a36Sopenharmony_ci		0x41, 0x00, /* 0E-0F */
43862306a36Sopenharmony_ci		0x3C, 0x00, /* 10-11 */
43962306a36Sopenharmony_ci		0x17,	/* 12 */
44062306a36Sopenharmony_ci		0x21,	/* 13 */
44162306a36Sopenharmony_ci		0x1B, 0x1B, 0x24, /* 14-16 */
44262306a36Sopenharmony_ci		0x83, 0x01, /* 17-18 */
44362306a36Sopenharmony_ci		0x00,	/* 19 */
44462306a36Sopenharmony_ci		0x0F,	/* 1A */
44562306a36Sopenharmony_ci		0x0F,	/* 1B */
44662306a36Sopenharmony_ci		0x60,	/* 1C */
44762306a36Sopenharmony_ci		0x05,	/* 1D */
44862306a36Sopenharmony_ci		0x89, 0x02, /* 1E-1F */
44962306a36Sopenharmony_ci		0x5F,	/* 20 */
45062306a36Sopenharmony_ci		0x04,	/* 21 */
45162306a36Sopenharmony_ci		0x5F,	/* 22 */
45262306a36Sopenharmony_ci		0x01,	/* 23 */
45362306a36Sopenharmony_ci		0x02,	/* 24 */
45462306a36Sopenharmony_ci		0x00,	/* 25 */
45562306a36Sopenharmony_ci		0x0A,	/* 26 */
45662306a36Sopenharmony_ci		0x05,	/* 27 */
45762306a36Sopenharmony_ci		0x00,	/* 28 */
45862306a36Sopenharmony_ci		0x10,	/* 29 */
45962306a36Sopenharmony_ci		0xFF, 0x03, /* 2A-2B */
46062306a36Sopenharmony_ci		0x24,	/* 2C */
46162306a36Sopenharmony_ci		0x0F, 0x78, /* 2D-2E */
46262306a36Sopenharmony_ci		0x00, 0x00, /* 2F-30 */
46362306a36Sopenharmony_ci		0xB2, 0x04, /* 31-32 */
46462306a36Sopenharmony_ci		0x14,	/* 33 */
46562306a36Sopenharmony_ci		0x02,	/* 34 */
46662306a36Sopenharmony_ci		0x00,	/* 35 written multiple times */
46762306a36Sopenharmony_ci		0x00,	/* 36 not written */
46862306a36Sopenharmony_ci		0xA3,	/* 37 */
46962306a36Sopenharmony_ci		0xC8,	/* 38 */
47062306a36Sopenharmony_ci		0x15,	/* 39 */
47162306a36Sopenharmony_ci		0x05,	/* 3A */
47262306a36Sopenharmony_ci		0x3B,	/* 3B */
47362306a36Sopenharmony_ci		0x3C, 0x00, /* 3C-3D */
47462306a36Sopenharmony_ci		0x00,	/* 3E written multiple times */
47562306a36Sopenharmony_ci		0x00,	/* never written */
47662306a36Sopenharmony_ci	}, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 };
47762306a36Sopenharmony_ci	struct matrox_fb_info *minfo = md->primary_head;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	if (minfo->outputs[1].mode == MATROXFB_OUTPUT_MODE_PAL)
48062306a36Sopenharmony_ci		*data = palregs;
48162306a36Sopenharmony_ci	else
48262306a36Sopenharmony_ci		*data = ntscregs;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	/* Set deflicker */
48562306a36Sopenharmony_ci	data->regs[0x93] = maven_compute_deflicker(md);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	/* set gamma */
48862306a36Sopenharmony_ci	{
48962306a36Sopenharmony_ci		const struct maven_gamma* g;
49062306a36Sopenharmony_ci		g = maven_compute_gamma(md);
49162306a36Sopenharmony_ci		data->regs[0x83] = g->reg83;
49262306a36Sopenharmony_ci		data->regs[0x84] = g->reg84;
49362306a36Sopenharmony_ci		data->regs[0x85] = g->reg85;
49462306a36Sopenharmony_ci		data->regs[0x86] = g->reg86;
49562306a36Sopenharmony_ci		data->regs[0x87] = g->reg87;
49662306a36Sopenharmony_ci		data->regs[0x88] = g->reg88;
49762306a36Sopenharmony_ci		data->regs[0x89] = g->reg89;
49862306a36Sopenharmony_ci		data->regs[0x8A] = g->reg8a;
49962306a36Sopenharmony_ci		data->regs[0x8B] = g->reg8b;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	/* Set contrast / brightness */
50362306a36Sopenharmony_ci	{
50462306a36Sopenharmony_ci		int bl, wl;
50562306a36Sopenharmony_ci		maven_compute_bwlevel (md, &bl, &wl);
50662306a36Sopenharmony_ci		data->regs[0x0e] = bl >> 2;
50762306a36Sopenharmony_ci		data->regs[0x0f] = bl & 3;
50862306a36Sopenharmony_ci		data->regs[0x1e] = wl >> 2;
50962306a36Sopenharmony_ci		data->regs[0x1f] = wl & 3;
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* Set saturation */
51362306a36Sopenharmony_ci	{
51462306a36Sopenharmony_ci		data->regs[0x20] =
51562306a36Sopenharmony_ci		data->regs[0x22] = minfo->altout.tvo_params.saturation;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* Set HUE */
51962306a36Sopenharmony_ci	data->regs[0x25] = minfo->altout.tvo_params.hue;
52062306a36Sopenharmony_ci	return;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci#define LR(x) maven_set_reg(c, (x), m->regs[(x)])
52462306a36Sopenharmony_ci#define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8))
52562306a36Sopenharmony_cistatic void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) {
52662306a36Sopenharmony_ci	int val;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	maven_set_reg(c, 0x3E, 0x01);
53062306a36Sopenharmony_ci	maven_get_reg(c, 0x82);	/* fetch oscillator state? */
53162306a36Sopenharmony_ci	maven_set_reg(c, 0x8C, 0x00);
53262306a36Sopenharmony_ci	maven_get_reg(c, 0x94);	/* get 0x82 */
53362306a36Sopenharmony_ci	maven_set_reg(c, 0x94, 0xA2);
53462306a36Sopenharmony_ci	/* xmiscctrl */
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	maven_set_reg_pair(c, 0x8E, 0x1EFF);
53762306a36Sopenharmony_ci	maven_set_reg(c, 0xC6, 0x01);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/* removed code... */
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	maven_get_reg(c, 0x06);
54262306a36Sopenharmony_ci	maven_set_reg(c, 0x06, 0xF9);	/* or read |= 0xF0 ? */
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* removed code here... */
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	/* real code begins here? */
54762306a36Sopenharmony_ci	/* chroma subcarrier */
54862306a36Sopenharmony_ci	LR(0x00); LR(0x01); LR(0x02); LR(0x03);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	LR(0x04);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	LR(0x2C);
55362306a36Sopenharmony_ci	LR(0x08);
55462306a36Sopenharmony_ci	LR(0x0A);
55562306a36Sopenharmony_ci	LR(0x09);
55662306a36Sopenharmony_ci	LR(0x29);
55762306a36Sopenharmony_ci	LRP(0x31);
55862306a36Sopenharmony_ci	LRP(0x17);
55962306a36Sopenharmony_ci	LR(0x0B);
56062306a36Sopenharmony_ci	LR(0x0C);
56162306a36Sopenharmony_ci	if (m->mode == MATROXFB_OUTPUT_MODE_PAL) {
56262306a36Sopenharmony_ci		maven_set_reg(c, 0x35, 0x10); /* ... */
56362306a36Sopenharmony_ci	} else {
56462306a36Sopenharmony_ci		maven_set_reg(c, 0x35, 0x0F); /* ... */
56562306a36Sopenharmony_ci	}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	LRP(0x10);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	LRP(0x0E);
57062306a36Sopenharmony_ci	LRP(0x1E);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	LR(0x20);	/* saturation #1 */
57362306a36Sopenharmony_ci	LR(0x22);	/* saturation #2 */
57462306a36Sopenharmony_ci	LR(0x25);	/* hue */
57562306a36Sopenharmony_ci	LR(0x34);
57662306a36Sopenharmony_ci	LR(0x33);
57762306a36Sopenharmony_ci	LR(0x19);
57862306a36Sopenharmony_ci	LR(0x12);
57962306a36Sopenharmony_ci	LR(0x3B);
58062306a36Sopenharmony_ci	LR(0x13);
58162306a36Sopenharmony_ci	LR(0x39);
58262306a36Sopenharmony_ci	LR(0x1D);
58362306a36Sopenharmony_ci	LR(0x3A);
58462306a36Sopenharmony_ci	LR(0x24);
58562306a36Sopenharmony_ci	LR(0x14);
58662306a36Sopenharmony_ci	LR(0x15);
58762306a36Sopenharmony_ci	LR(0x16);
58862306a36Sopenharmony_ci	LRP(0x2D);
58962306a36Sopenharmony_ci	LRP(0x2F);
59062306a36Sopenharmony_ci	LR(0x1A);
59162306a36Sopenharmony_ci	LR(0x1B);
59262306a36Sopenharmony_ci	LR(0x1C);
59362306a36Sopenharmony_ci	LR(0x23);
59462306a36Sopenharmony_ci	LR(0x26);
59562306a36Sopenharmony_ci	LR(0x28);
59662306a36Sopenharmony_ci	LR(0x27);
59762306a36Sopenharmony_ci	LR(0x21);
59862306a36Sopenharmony_ci	LRP(0x2A);
59962306a36Sopenharmony_ci	if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
60062306a36Sopenharmony_ci		maven_set_reg(c, 0x35, 0x1D);	/* ... */
60162306a36Sopenharmony_ci	else
60262306a36Sopenharmony_ci		maven_set_reg(c, 0x35, 0x1C);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	LRP(0x3C);
60562306a36Sopenharmony_ci	LR(0x37);
60662306a36Sopenharmony_ci	LR(0x38);
60762306a36Sopenharmony_ci	maven_set_reg(c, 0xB3, 0x01);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	maven_get_reg(c, 0xB0);	/* read 0x80 */
61062306a36Sopenharmony_ci	maven_set_reg(c, 0xB0, 0x08);	/* ugh... */
61162306a36Sopenharmony_ci	maven_get_reg(c, 0xB9);	/* read 0x7C */
61262306a36Sopenharmony_ci	maven_set_reg(c, 0xB9, 0x78);
61362306a36Sopenharmony_ci	maven_get_reg(c, 0xBF);	/* read 0x00 */
61462306a36Sopenharmony_ci	maven_set_reg(c, 0xBF, 0x02);
61562306a36Sopenharmony_ci	maven_get_reg(c, 0x94);	/* read 0x82 */
61662306a36Sopenharmony_ci	maven_set_reg(c, 0x94, 0xB3);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	LR(0x80); /* 04 1A 91 or 05 21 91 */
61962306a36Sopenharmony_ci	LR(0x81);
62062306a36Sopenharmony_ci	LR(0x82);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	maven_set_reg(c, 0x8C, 0x20);
62362306a36Sopenharmony_ci	maven_get_reg(c, 0x8D);
62462306a36Sopenharmony_ci	maven_set_reg(c, 0x8D, 0x10);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	LR(0x90); /* 4D 50 52 or 4E 05 45 */
62762306a36Sopenharmony_ci	LR(0x91);
62862306a36Sopenharmony_ci	LR(0x92);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	LRP(0x9A); /* 0049 or 004F */
63162306a36Sopenharmony_ci	LRP(0x9C); /* 0004 or 0004 */
63262306a36Sopenharmony_ci	LRP(0x9E); /* 0458 or 045E */
63362306a36Sopenharmony_ci	LRP(0xA0); /* 05DA or 051B */
63462306a36Sopenharmony_ci	LRP(0xA2); /* 00CC or 00CF */
63562306a36Sopenharmony_ci	LRP(0xA4); /* 007D or 007F */
63662306a36Sopenharmony_ci	LRP(0xA6); /* 007C or 007E */
63762306a36Sopenharmony_ci	LRP(0xA8); /* 03CB or 03CE */
63862306a36Sopenharmony_ci	LRP(0x98); /* 0000 or 0000 */
63962306a36Sopenharmony_ci	LRP(0xAE); /* 0044 or 003A */
64062306a36Sopenharmony_ci	LRP(0x96); /* 05DA or 051B */
64162306a36Sopenharmony_ci	LRP(0xAA); /* 04BC or 046A */
64262306a36Sopenharmony_ci	LRP(0xAC); /* 004D or 004E */
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	LR(0xBE);
64562306a36Sopenharmony_ci	LR(0xC2);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	maven_get_reg(c, 0x8D);
64862306a36Sopenharmony_ci	maven_set_reg(c, 0x8D, 0x04);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	LR(0x20);	/* saturation #1 */
65162306a36Sopenharmony_ci	LR(0x22);	/* saturation #2 */
65262306a36Sopenharmony_ci	LR(0x93);	/* whoops */
65362306a36Sopenharmony_ci	LR(0x20);	/* oh, saturation #1 again */
65462306a36Sopenharmony_ci	LR(0x22);	/* oh, saturation #2 again */
65562306a36Sopenharmony_ci	LR(0x25);	/* hue */
65662306a36Sopenharmony_ci	LRP(0x0E);
65762306a36Sopenharmony_ci	LRP(0x1E);
65862306a36Sopenharmony_ci	LRP(0x0E);	/* problems with memory? */
65962306a36Sopenharmony_ci	LRP(0x1E);	/* yes, matrox must have problems in memory area... */
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	/* load gamma correction stuff */
66262306a36Sopenharmony_ci	LR(0x83);
66362306a36Sopenharmony_ci	LR(0x84);
66462306a36Sopenharmony_ci	LR(0x85);
66562306a36Sopenharmony_ci	LR(0x86);
66662306a36Sopenharmony_ci	LR(0x87);
66762306a36Sopenharmony_ci	LR(0x88);
66862306a36Sopenharmony_ci	LR(0x89);
66962306a36Sopenharmony_ci	LR(0x8A);
67062306a36Sopenharmony_ci	LR(0x8B);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	val = maven_get_reg(c, 0x8D);
67362306a36Sopenharmony_ci	val &= 0x14;			/* 0x10 or anything ored with it */
67462306a36Sopenharmony_ci	maven_set_reg(c, 0x8D, val);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	LR(0x33);
67762306a36Sopenharmony_ci	LR(0x19);
67862306a36Sopenharmony_ci	LR(0x12);
67962306a36Sopenharmony_ci	LR(0x3B);
68062306a36Sopenharmony_ci	LR(0x13);
68162306a36Sopenharmony_ci	LR(0x39);
68262306a36Sopenharmony_ci	LR(0x1D);
68362306a36Sopenharmony_ci	LR(0x3A);
68462306a36Sopenharmony_ci	LR(0x24);
68562306a36Sopenharmony_ci	LR(0x14);
68662306a36Sopenharmony_ci	LR(0x15);
68762306a36Sopenharmony_ci	LR(0x16);
68862306a36Sopenharmony_ci	LRP(0x2D);
68962306a36Sopenharmony_ci	LRP(0x2F);
69062306a36Sopenharmony_ci	LR(0x1A);
69162306a36Sopenharmony_ci	LR(0x1B);
69262306a36Sopenharmony_ci	LR(0x1C);
69362306a36Sopenharmony_ci	LR(0x23);
69462306a36Sopenharmony_ci	LR(0x26);
69562306a36Sopenharmony_ci	LR(0x28);
69662306a36Sopenharmony_ci	LR(0x27);
69762306a36Sopenharmony_ci	LR(0x21);
69862306a36Sopenharmony_ci	LRP(0x2A);
69962306a36Sopenharmony_ci	if (m->mode == MATROXFB_OUTPUT_MODE_PAL)
70062306a36Sopenharmony_ci		maven_set_reg(c, 0x35, 0x1D);
70162306a36Sopenharmony_ci	else
70262306a36Sopenharmony_ci		maven_set_reg(c, 0x35, 0x1C);
70362306a36Sopenharmony_ci	LRP(0x3C);
70462306a36Sopenharmony_ci	LR(0x37);
70562306a36Sopenharmony_ci	LR(0x38);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	maven_get_reg(c, 0xB0);
70862306a36Sopenharmony_ci	LR(0xB0);	/* output mode */
70962306a36Sopenharmony_ci	LR(0x90);
71062306a36Sopenharmony_ci	LR(0xBE);
71162306a36Sopenharmony_ci	LR(0xC2);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	LRP(0x9A);
71462306a36Sopenharmony_ci	LRP(0xA2);
71562306a36Sopenharmony_ci	LRP(0x9E);
71662306a36Sopenharmony_ci	LRP(0xA6);
71762306a36Sopenharmony_ci	LRP(0xAA);
71862306a36Sopenharmony_ci	LRP(0xAC);
71962306a36Sopenharmony_ci	maven_set_reg(c, 0x3E, 0x00);
72062306a36Sopenharmony_ci	maven_set_reg(c, 0x95, 0x20);
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
72462306a36Sopenharmony_ci		struct mavenregs* m) {
72562306a36Sopenharmony_ci	unsigned int x;
72662306a36Sopenharmony_ci	unsigned int err = ~0;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	/* 1:1 */
72962306a36Sopenharmony_ci	m->regs[0x80] = 0x0F;
73062306a36Sopenharmony_ci	m->regs[0x81] = 0x07;
73162306a36Sopenharmony_ci	m->regs[0x82] = 0x81;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	for (x = 0; x < 8; x++) {
73462306a36Sopenharmony_ci		unsigned int c;
73562306a36Sopenharmony_ci		unsigned int a, b,
73662306a36Sopenharmony_ci			     h2;
73762306a36Sopenharmony_ci		unsigned int h = ht + 2 + x;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
74062306a36Sopenharmony_ci			unsigned int diff = h - h2;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci			if (diff < err) {
74362306a36Sopenharmony_ci				err = diff;
74462306a36Sopenharmony_ci				m->regs[0x80] = a - 1;
74562306a36Sopenharmony_ci				m->regs[0x81] = b - 1;
74662306a36Sopenharmony_ci				m->regs[0x82] = c | 0x80;
74762306a36Sopenharmony_ci				m->hcorr = h2 - 2;
74862306a36Sopenharmony_ci				m->htotal = h - 2;
74962306a36Sopenharmony_ci			}
75062306a36Sopenharmony_ci		}
75162306a36Sopenharmony_ci	}
75262306a36Sopenharmony_ci	return err != ~0U;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic inline int maven_compute_timming(struct maven_data* md,
75662306a36Sopenharmony_ci		struct my_timming* mt,
75762306a36Sopenharmony_ci		struct mavenregs* m) {
75862306a36Sopenharmony_ci	unsigned int tmpi;
75962306a36Sopenharmony_ci	unsigned int a, bv, c;
76062306a36Sopenharmony_ci	struct matrox_fb_info *minfo = md->primary_head;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	m->mode = minfo->outputs[1].mode;
76362306a36Sopenharmony_ci	if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) {
76462306a36Sopenharmony_ci		unsigned int lmargin;
76562306a36Sopenharmony_ci		unsigned int umargin;
76662306a36Sopenharmony_ci		unsigned int vslen;
76762306a36Sopenharmony_ci		unsigned int hcrt;
76862306a36Sopenharmony_ci		unsigned int slen;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci		maven_init_TVdata(md, m);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0)
77362306a36Sopenharmony_ci			return -EINVAL;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci		lmargin = mt->HTotal - mt->HSyncEnd;
77662306a36Sopenharmony_ci		slen = mt->HSyncEnd - mt->HSyncStart;
77762306a36Sopenharmony_ci		hcrt = mt->HTotal - slen - mt->delay;
77862306a36Sopenharmony_ci		umargin = mt->VTotal - mt->VSyncEnd;
77962306a36Sopenharmony_ci		vslen = mt->VSyncEnd - mt->VSyncStart;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci		if (m->hcorr < mt->HTotal)
78262306a36Sopenharmony_ci			hcrt += m->hcorr;
78362306a36Sopenharmony_ci		if (hcrt > mt->HTotal)
78462306a36Sopenharmony_ci			hcrt -= mt->HTotal;
78562306a36Sopenharmony_ci		if (hcrt + 2 > mt->HTotal)
78662306a36Sopenharmony_ci			hcrt = 0;	/* or issue warning? */
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci		/* last (first? middle?) line in picture can have different length */
78962306a36Sopenharmony_ci		/* hlen - 2 */
79062306a36Sopenharmony_ci		m->regs[0x96] = m->hcorr;
79162306a36Sopenharmony_ci		m->regs[0x97] = m->hcorr >> 8;
79262306a36Sopenharmony_ci		/* ... */
79362306a36Sopenharmony_ci		m->regs[0x98] = 0x00; m->regs[0x99] = 0x00;
79462306a36Sopenharmony_ci		/* hblanking end */
79562306a36Sopenharmony_ci		m->regs[0x9A] = lmargin;	/* 100% */
79662306a36Sopenharmony_ci		m->regs[0x9B] = lmargin >> 8;	/* 100% */
79762306a36Sopenharmony_ci		/* who knows */
79862306a36Sopenharmony_ci		m->regs[0x9C] = 0x04;
79962306a36Sopenharmony_ci		m->regs[0x9D] = 0x00;
80062306a36Sopenharmony_ci		/* htotal - 2 */
80162306a36Sopenharmony_ci		m->regs[0xA0] = m->htotal;
80262306a36Sopenharmony_ci		m->regs[0xA1] = m->htotal >> 8;
80362306a36Sopenharmony_ci		/* vblanking end */
80462306a36Sopenharmony_ci		m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1;	/* stop vblanking */
80562306a36Sopenharmony_ci		m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8;
80662306a36Sopenharmony_ci		/* something end... [A6]+1..[A8] */
80762306a36Sopenharmony_ci		if (md->version == MGATVO_B) {
80862306a36Sopenharmony_ci			m->regs[0xA4] = 0x04;
80962306a36Sopenharmony_ci			m->regs[0xA5] = 0x00;
81062306a36Sopenharmony_ci		} else {
81162306a36Sopenharmony_ci			m->regs[0xA4] = 0x01;
81262306a36Sopenharmony_ci			m->regs[0xA5] = 0x00;
81362306a36Sopenharmony_ci		}
81462306a36Sopenharmony_ci		/* something start... 0..[A4]-1 */
81562306a36Sopenharmony_ci		m->regs[0xA6] = 0x00;
81662306a36Sopenharmony_ci		m->regs[0xA7] = 0x00;
81762306a36Sopenharmony_ci		/* vertical line count - 1 */
81862306a36Sopenharmony_ci		m->regs[0xA8] = mt->VTotal - 1;
81962306a36Sopenharmony_ci		m->regs[0xA9] = (mt->VTotal - 1) >> 8;
82062306a36Sopenharmony_ci		/* horizontal vidrst pos */
82162306a36Sopenharmony_ci		m->regs[0xAA] = hcrt;		/* 0 <= hcrt <= htotal - 2 */
82262306a36Sopenharmony_ci		m->regs[0xAB] = hcrt >> 8;
82362306a36Sopenharmony_ci		/* vertical vidrst pos */
82462306a36Sopenharmony_ci		m->regs[0xAC] = mt->VTotal - 2;
82562306a36Sopenharmony_ci		m->regs[0xAD] = (mt->VTotal - 2) >> 8;
82662306a36Sopenharmony_ci		/* moves picture up/down and so on... */
82762306a36Sopenharmony_ci		m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */
82862306a36Sopenharmony_ci		m->regs[0xAF] = 0x00;
82962306a36Sopenharmony_ci		{
83062306a36Sopenharmony_ci			int hdec;
83162306a36Sopenharmony_ci			int hlen;
83262306a36Sopenharmony_ci			unsigned int ibmin = 4 + lmargin + mt->HDisplay;
83362306a36Sopenharmony_ci			unsigned int ib;
83462306a36Sopenharmony_ci			int i;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci			/* Verify! */
83762306a36Sopenharmony_ci			/* Where 94208 came from? */
83862306a36Sopenharmony_ci			if (mt->HTotal)
83962306a36Sopenharmony_ci				hdec = 94208 / (mt->HTotal);
84062306a36Sopenharmony_ci			else
84162306a36Sopenharmony_ci				hdec = 0x81;
84262306a36Sopenharmony_ci			if (hdec > 0x81)
84362306a36Sopenharmony_ci				hdec = 0x81;
84462306a36Sopenharmony_ci			if (hdec < 0x41)
84562306a36Sopenharmony_ci				hdec = 0x41;
84662306a36Sopenharmony_ci			hdec--;
84762306a36Sopenharmony_ci			hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec);
84862306a36Sopenharmony_ci			if (hlen < 0)
84962306a36Sopenharmony_ci				hlen = 0;
85062306a36Sopenharmony_ci			hlen = hlen >> 8;
85162306a36Sopenharmony_ci			if (hlen > 0xFF)
85262306a36Sopenharmony_ci				hlen = 0xFF;
85362306a36Sopenharmony_ci			/* Now we have to compute input buffer length.
85462306a36Sopenharmony_ci			   If you want any picture, it must be between
85562306a36Sopenharmony_ci			     4 + lmargin + xres
85662306a36Sopenharmony_ci			   and
85762306a36Sopenharmony_ci			     94208 / hdec
85862306a36Sopenharmony_ci			   If you want perfect picture even on the top
85962306a36Sopenharmony_ci			   of screen, it must be also
86062306a36Sopenharmony_ci			     0x3C0000 * i / hdec + Q - R / hdec
86162306a36Sopenharmony_ci			   where
86262306a36Sopenharmony_ci			        R      Qmin   Qmax
86362306a36Sopenharmony_ci			     0x07000   0x5AE  0x5BF
86462306a36Sopenharmony_ci			     0x08000   0x5CF  0x5FF
86562306a36Sopenharmony_ci			     0x0C000   0x653  0x67F
86662306a36Sopenharmony_ci			     0x10000   0x6F8  0x6FF
86762306a36Sopenharmony_ci			 */
86862306a36Sopenharmony_ci			i = 1;
86962306a36Sopenharmony_ci			do {
87062306a36Sopenharmony_ci				ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8;
87162306a36Sopenharmony_ci				i++;
87262306a36Sopenharmony_ci			} while (ib < ibmin);
87362306a36Sopenharmony_ci			if (ib >= m->htotal + 2) {
87462306a36Sopenharmony_ci				ib = ibmin;
87562306a36Sopenharmony_ci			}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci			m->regs[0x90] = hdec;	/* < 0x40 || > 0x80 is bad... 0x80 is questionable */
87862306a36Sopenharmony_ci			m->regs[0xC2] = hlen;
87962306a36Sopenharmony_ci			/* 'valid' input line length */
88062306a36Sopenharmony_ci			m->regs[0x9E] = ib;
88162306a36Sopenharmony_ci			m->regs[0x9F] = ib >> 8;
88262306a36Sopenharmony_ci		}
88362306a36Sopenharmony_ci		{
88462306a36Sopenharmony_ci			int vdec;
88562306a36Sopenharmony_ci			int vlen;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci#define MATROX_USE64BIT_DIVIDE
88862306a36Sopenharmony_ci			if (mt->VTotal) {
88962306a36Sopenharmony_ci#ifdef MATROX_USE64BIT_DIVIDE
89062306a36Sopenharmony_ci				u64 f1;
89162306a36Sopenharmony_ci				u32 a;
89262306a36Sopenharmony_ci				u32 b;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci				a = m->vlines * (m->htotal + 2);
89562306a36Sopenharmony_ci				b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci				f1 = ((u64)a) << 15;	/* *32768 */
89862306a36Sopenharmony_ci				do_div(f1, b);
89962306a36Sopenharmony_ci				vdec = f1;
90062306a36Sopenharmony_ci#else
90162306a36Sopenharmony_ci				vdec = m->vlines * 32768 / mt->VTotal;
90262306a36Sopenharmony_ci#endif
90362306a36Sopenharmony_ci			} else
90462306a36Sopenharmony_ci				vdec = 0x8000;
90562306a36Sopenharmony_ci			if (vdec > 0x8000)
90662306a36Sopenharmony_ci				vdec = 0x8000;
90762306a36Sopenharmony_ci			vlen = (vslen + umargin + mt->VDisplay) * vdec;
90862306a36Sopenharmony_ci			vlen = (vlen >> 16) - 146; /* FIXME: 146?! */
90962306a36Sopenharmony_ci			if (vlen < 0)
91062306a36Sopenharmony_ci				vlen = 0;
91162306a36Sopenharmony_ci			if (vlen > 0xFF)
91262306a36Sopenharmony_ci				vlen = 0xFF;
91362306a36Sopenharmony_ci			vdec--;
91462306a36Sopenharmony_ci			m->regs[0x91] = vdec;
91562306a36Sopenharmony_ci			m->regs[0x92] = vdec >> 8;
91662306a36Sopenharmony_ci			m->regs[0xBE] = vlen;
91762306a36Sopenharmony_ci		}
91862306a36Sopenharmony_ci		m->regs[0xB0] = 0x08;	/* output: SVideo/Composite */
91962306a36Sopenharmony_ci		return 0;
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c);
92362306a36Sopenharmony_ci	m->regs[0x80] = a;
92462306a36Sopenharmony_ci	m->regs[0x81] = bv;
92562306a36Sopenharmony_ci	m->regs[0x82] = c | 0x80;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	m->regs[0xB3] = 0x01;
92862306a36Sopenharmony_ci	m->regs[0x94] = 0xB2;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	/* htotal... */
93162306a36Sopenharmony_ci	m->regs[0x96] = mt->HTotal;
93262306a36Sopenharmony_ci	m->regs[0x97] = mt->HTotal >> 8;
93362306a36Sopenharmony_ci	/* ?? */
93462306a36Sopenharmony_ci	m->regs[0x98] = 0x00;
93562306a36Sopenharmony_ci	m->regs[0x99] = 0x00;
93662306a36Sopenharmony_ci	/* hsync len */
93762306a36Sopenharmony_ci	tmpi = mt->HSyncEnd - mt->HSyncStart;
93862306a36Sopenharmony_ci	m->regs[0x9A] = tmpi;
93962306a36Sopenharmony_ci	m->regs[0x9B] = tmpi >> 8;
94062306a36Sopenharmony_ci	/* hblank end */
94162306a36Sopenharmony_ci	tmpi = mt->HTotal - mt->HSyncStart;
94262306a36Sopenharmony_ci	m->regs[0x9C] = tmpi;
94362306a36Sopenharmony_ci	m->regs[0x9D] = tmpi >> 8;
94462306a36Sopenharmony_ci	/* hblank start */
94562306a36Sopenharmony_ci	tmpi += mt->HDisplay;
94662306a36Sopenharmony_ci	m->regs[0x9E] = tmpi;
94762306a36Sopenharmony_ci	m->regs[0x9F] = tmpi >> 8;
94862306a36Sopenharmony_ci	/* htotal + 1 */
94962306a36Sopenharmony_ci	tmpi = mt->HTotal + 1;
95062306a36Sopenharmony_ci	m->regs[0xA0] = tmpi;
95162306a36Sopenharmony_ci	m->regs[0xA1] = tmpi >> 8;
95262306a36Sopenharmony_ci	/* vsync?! */
95362306a36Sopenharmony_ci	tmpi = mt->VSyncEnd - mt->VSyncStart - 1;
95462306a36Sopenharmony_ci	m->regs[0xA2] = tmpi;
95562306a36Sopenharmony_ci	m->regs[0xA3] = tmpi >> 8;
95662306a36Sopenharmony_ci	/* ignored? */
95762306a36Sopenharmony_ci	tmpi = mt->VTotal - mt->VSyncStart;
95862306a36Sopenharmony_ci	m->regs[0xA4] = tmpi;
95962306a36Sopenharmony_ci	m->regs[0xA5] = tmpi >> 8;
96062306a36Sopenharmony_ci	/* ignored? */
96162306a36Sopenharmony_ci	tmpi = mt->VTotal - 1;
96262306a36Sopenharmony_ci	m->regs[0xA6] = tmpi;
96362306a36Sopenharmony_ci	m->regs[0xA7] = tmpi >> 8;
96462306a36Sopenharmony_ci	/* vtotal - 1 */
96562306a36Sopenharmony_ci	m->regs[0xA8] = tmpi;
96662306a36Sopenharmony_ci	m->regs[0xA9] = tmpi >> 8;
96762306a36Sopenharmony_ci	/* hor vidrst */
96862306a36Sopenharmony_ci	tmpi = mt->HTotal - mt->delay;
96962306a36Sopenharmony_ci	m->regs[0xAA] = tmpi;
97062306a36Sopenharmony_ci	m->regs[0xAB] = tmpi >> 8;
97162306a36Sopenharmony_ci	/* vert vidrst */
97262306a36Sopenharmony_ci	tmpi = mt->VTotal - 2;
97362306a36Sopenharmony_ci	m->regs[0xAC] = tmpi;
97462306a36Sopenharmony_ci	m->regs[0xAD] = tmpi >> 8;
97562306a36Sopenharmony_ci	/* ignored? */
97662306a36Sopenharmony_ci	m->regs[0xAE] = 0x00;
97762306a36Sopenharmony_ci	m->regs[0xAF] = 0x00;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	m->regs[0xB0] = 0x03;	/* output: monitor */
98062306a36Sopenharmony_ci	m->regs[0xB1] = 0xA0;	/* ??? */
98162306a36Sopenharmony_ci	m->regs[0x8C] = 0x20;	/* must be set... */
98262306a36Sopenharmony_ci	m->regs[0x8D] = 0x04;	/* defaults to 0x10: test signal */
98362306a36Sopenharmony_ci	m->regs[0xB9] = 0x1A;	/* defaults to 0x2C: too bright */
98462306a36Sopenharmony_ci	m->regs[0xBF] = 0x22;	/* makes picture stable */
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	return 0;
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic int maven_program_timming(struct maven_data* md,
99062306a36Sopenharmony_ci		const struct mavenregs* m) {
99162306a36Sopenharmony_ci	struct i2c_client *c = md->client;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) {
99462306a36Sopenharmony_ci		LR(0x80);
99562306a36Sopenharmony_ci		LR(0x81);
99662306a36Sopenharmony_ci		LR(0x82);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci		LR(0xB3);
99962306a36Sopenharmony_ci		LR(0x94);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci		LRP(0x96);
100262306a36Sopenharmony_ci		LRP(0x98);
100362306a36Sopenharmony_ci		LRP(0x9A);
100462306a36Sopenharmony_ci		LRP(0x9C);
100562306a36Sopenharmony_ci		LRP(0x9E);
100662306a36Sopenharmony_ci		LRP(0xA0);
100762306a36Sopenharmony_ci		LRP(0xA2);
100862306a36Sopenharmony_ci		LRP(0xA4);
100962306a36Sopenharmony_ci		LRP(0xA6);
101062306a36Sopenharmony_ci		LRP(0xA8);
101162306a36Sopenharmony_ci		LRP(0xAA);
101262306a36Sopenharmony_ci		LRP(0xAC);
101362306a36Sopenharmony_ci		LRP(0xAE);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci		LR(0xB0);	/* output: monitor */
101662306a36Sopenharmony_ci		LR(0xB1);	/* ??? */
101762306a36Sopenharmony_ci		LR(0x8C);	/* must be set... */
101862306a36Sopenharmony_ci		LR(0x8D);	/* defaults to 0x10: test signal */
101962306a36Sopenharmony_ci		LR(0xB9);	/* defaults to 0x2C: too bright */
102062306a36Sopenharmony_ci		LR(0xBF);	/* makes picture stable */
102162306a36Sopenharmony_ci	} else {
102262306a36Sopenharmony_ci		maven_init_TV(c, m);
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci	return 0;
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_cistatic inline int maven_resync(struct maven_data* md) {
102862306a36Sopenharmony_ci	struct i2c_client *c = md->client;
102962306a36Sopenharmony_ci	maven_set_reg(c, 0x95, 0x20);	/* start whole thing */
103062306a36Sopenharmony_ci	return 0;
103162306a36Sopenharmony_ci}
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_cistatic int maven_get_queryctrl (struct maven_data* md,
103462306a36Sopenharmony_ci				struct v4l2_queryctrl *p) {
103562306a36Sopenharmony_ci	int i;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	i = get_ctrl_id(p->id);
103862306a36Sopenharmony_ci	if (i >= 0) {
103962306a36Sopenharmony_ci		*p = maven_controls[i].desc;
104062306a36Sopenharmony_ci		return 0;
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci	if (i == -ENOENT) {
104362306a36Sopenharmony_ci		static const struct v4l2_queryctrl disctrl =
104462306a36Sopenharmony_ci			{ .flags = V4L2_CTRL_FLAG_DISABLED };
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci		i = p->id;
104762306a36Sopenharmony_ci		*p = disctrl;
104862306a36Sopenharmony_ci		p->id = i;
104962306a36Sopenharmony_ci		sprintf(p->name, "Ctrl #%08X", i);
105062306a36Sopenharmony_ci		return 0;
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci	return -EINVAL;
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_cistatic int maven_set_control (struct maven_data* md,
105662306a36Sopenharmony_ci			      struct v4l2_control *p) {
105762306a36Sopenharmony_ci	int i;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	i = get_ctrl_id(p->id);
106062306a36Sopenharmony_ci	if (i < 0) return -EINVAL;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/*
106362306a36Sopenharmony_ci	 * Check if changed.
106462306a36Sopenharmony_ci	 */
106562306a36Sopenharmony_ci	if (p->value == *get_ctrl_ptr(md, i)) return 0;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	/*
106862306a36Sopenharmony_ci	 * Check limits.
106962306a36Sopenharmony_ci	 */
107062306a36Sopenharmony_ci	if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
107162306a36Sopenharmony_ci	if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	/*
107462306a36Sopenharmony_ci	 * Store new value.
107562306a36Sopenharmony_ci	 */
107662306a36Sopenharmony_ci	*get_ctrl_ptr(md, i) = p->value;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	switch (p->id) {
107962306a36Sopenharmony_ci		case V4L2_CID_BRIGHTNESS:
108062306a36Sopenharmony_ci		case V4L2_CID_CONTRAST:
108162306a36Sopenharmony_ci		{
108262306a36Sopenharmony_ci		  int blacklevel, whitelevel;
108362306a36Sopenharmony_ci		  maven_compute_bwlevel(md, &blacklevel, &whitelevel);
108462306a36Sopenharmony_ci		  blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
108562306a36Sopenharmony_ci		  whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
108662306a36Sopenharmony_ci		  maven_set_reg_pair(md->client, 0x0e, blacklevel);
108762306a36Sopenharmony_ci		  maven_set_reg_pair(md->client, 0x1e, whitelevel);
108862306a36Sopenharmony_ci		}
108962306a36Sopenharmony_ci		break;
109062306a36Sopenharmony_ci		case V4L2_CID_SATURATION:
109162306a36Sopenharmony_ci		{
109262306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x20, p->value);
109362306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x22, p->value);
109462306a36Sopenharmony_ci		}
109562306a36Sopenharmony_ci		break;
109662306a36Sopenharmony_ci		case V4L2_CID_HUE:
109762306a36Sopenharmony_ci		{
109862306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x25, p->value);
109962306a36Sopenharmony_ci		}
110062306a36Sopenharmony_ci		break;
110162306a36Sopenharmony_ci		case V4L2_CID_GAMMA:
110262306a36Sopenharmony_ci		{
110362306a36Sopenharmony_ci		  const struct maven_gamma* g;
110462306a36Sopenharmony_ci		  g = maven_compute_gamma(md);
110562306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x83, g->reg83);
110662306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x84, g->reg84);
110762306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x85, g->reg85);
110862306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x86, g->reg86);
110962306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x87, g->reg87);
111062306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x88, g->reg88);
111162306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x89, g->reg89);
111262306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x8a, g->reg8a);
111362306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x8b, g->reg8b);
111462306a36Sopenharmony_ci		}
111562306a36Sopenharmony_ci		break;
111662306a36Sopenharmony_ci		case MATROXFB_CID_TESTOUT:
111762306a36Sopenharmony_ci		{
111862306a36Sopenharmony_ci			unsigned char val
111962306a36Sopenharmony_ci			  = maven_get_reg(md->client, 0x8d);
112062306a36Sopenharmony_ci			if (p->value) val |= 0x10;
112162306a36Sopenharmony_ci			else          val &= ~0x10;
112262306a36Sopenharmony_ci			maven_set_reg(md->client, 0x8d, val);
112362306a36Sopenharmony_ci		}
112462306a36Sopenharmony_ci		break;
112562306a36Sopenharmony_ci		case MATROXFB_CID_DEFLICKER:
112662306a36Sopenharmony_ci		{
112762306a36Sopenharmony_ci		  maven_set_reg(md->client, 0x93, maven_compute_deflicker(md));
112862306a36Sopenharmony_ci		}
112962306a36Sopenharmony_ci		break;
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	return 0;
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_cistatic int maven_get_control (struct maven_data* md,
113762306a36Sopenharmony_ci			      struct v4l2_control *p) {
113862306a36Sopenharmony_ci	int i;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	i = get_ctrl_id(p->id);
114162306a36Sopenharmony_ci	if (i < 0) return -EINVAL;
114262306a36Sopenharmony_ci	p->value = *get_ctrl_ptr(md, i);
114362306a36Sopenharmony_ci	return 0;
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci/******************************************************/
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_cistatic int maven_out_compute(void* md, struct my_timming* mt) {
114962306a36Sopenharmony_ci#define mdinfo ((struct maven_data*)md)
115062306a36Sopenharmony_ci#define minfo (mdinfo->primary_head)
115162306a36Sopenharmony_ci	return maven_compute_timming(md, mt, &minfo->hw.maven);
115262306a36Sopenharmony_ci#undef minfo
115362306a36Sopenharmony_ci#undef mdinfo
115462306a36Sopenharmony_ci}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_cistatic int maven_out_program(void* md) {
115762306a36Sopenharmony_ci#define mdinfo ((struct maven_data*)md)
115862306a36Sopenharmony_ci#define minfo (mdinfo->primary_head)
115962306a36Sopenharmony_ci	return maven_program_timming(md, &minfo->hw.maven);
116062306a36Sopenharmony_ci#undef minfo
116162306a36Sopenharmony_ci#undef mdinfo
116262306a36Sopenharmony_ci}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_cistatic int maven_out_start(void* md) {
116562306a36Sopenharmony_ci	return maven_resync(md);
116662306a36Sopenharmony_ci}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_cistatic int maven_out_verify_mode(void* md, u_int32_t arg) {
116962306a36Sopenharmony_ci	switch (arg) {
117062306a36Sopenharmony_ci		case MATROXFB_OUTPUT_MODE_PAL:
117162306a36Sopenharmony_ci		case MATROXFB_OUTPUT_MODE_NTSC:
117262306a36Sopenharmony_ci		case MATROXFB_OUTPUT_MODE_MONITOR:
117362306a36Sopenharmony_ci			return 0;
117462306a36Sopenharmony_ci	}
117562306a36Sopenharmony_ci	return -EINVAL;
117662306a36Sopenharmony_ci}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_cistatic int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) {
117962306a36Sopenharmony_ci        return maven_get_queryctrl(md, p);
118062306a36Sopenharmony_ci}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_cistatic int maven_out_get_ctrl(void* md, struct v4l2_control* p) {
118362306a36Sopenharmony_ci	return maven_get_control(md, p);
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_cistatic int maven_out_set_ctrl(void* md, struct v4l2_control* p) {
118762306a36Sopenharmony_ci	return maven_set_control(md, p);
118862306a36Sopenharmony_ci}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cistatic struct matrox_altout maven_altout = {
119162306a36Sopenharmony_ci	.name		= "Secondary output",
119262306a36Sopenharmony_ci	.compute	= maven_out_compute,
119362306a36Sopenharmony_ci	.program	= maven_out_program,
119462306a36Sopenharmony_ci	.start		= maven_out_start,
119562306a36Sopenharmony_ci	.verifymode	= maven_out_verify_mode,
119662306a36Sopenharmony_ci	.getqueryctrl	= maven_out_get_queryctrl,
119762306a36Sopenharmony_ci	.getctrl	= maven_out_get_ctrl,
119862306a36Sopenharmony_ci	.setctrl	= maven_out_set_ctrl,
119962306a36Sopenharmony_ci};
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_cistatic int maven_init_client(struct i2c_client* clnt) {
120262306a36Sopenharmony_ci	struct maven_data* md = i2c_get_clientdata(clnt);
120362306a36Sopenharmony_ci	struct matrox_fb_info *minfo = container_of(clnt->adapter,
120462306a36Sopenharmony_ci						    struct i2c_bit_adapter,
120562306a36Sopenharmony_ci						    adapter)->minfo;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	md->primary_head = minfo;
120862306a36Sopenharmony_ci	md->client = clnt;
120962306a36Sopenharmony_ci	down_write(&minfo->altout.lock);
121062306a36Sopenharmony_ci	minfo->outputs[1].output = &maven_altout;
121162306a36Sopenharmony_ci	minfo->outputs[1].src = minfo->outputs[1].default_src;
121262306a36Sopenharmony_ci	minfo->outputs[1].data = md;
121362306a36Sopenharmony_ci	minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
121462306a36Sopenharmony_ci	up_write(&minfo->altout.lock);
121562306a36Sopenharmony_ci	if (maven_get_reg(clnt, 0xB2) < 0x14) {
121662306a36Sopenharmony_ci		md->version = MGATVO_B;
121762306a36Sopenharmony_ci		/* Tweak some things for this old chip */
121862306a36Sopenharmony_ci	} else {
121962306a36Sopenharmony_ci		md->version = MGATVO_C;
122062306a36Sopenharmony_ci	}
122162306a36Sopenharmony_ci	/*
122262306a36Sopenharmony_ci	 * Set all parameters to its initial values.
122362306a36Sopenharmony_ci	 */
122462306a36Sopenharmony_ci	{
122562306a36Sopenharmony_ci		unsigned int i;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci		for (i = 0; i < MAVCTRLS; ++i) {
122862306a36Sopenharmony_ci			*get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
122962306a36Sopenharmony_ci		}
123062306a36Sopenharmony_ci	}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	return 0;
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic int maven_shutdown_client(struct i2c_client* clnt) {
123662306a36Sopenharmony_ci	struct maven_data* md = i2c_get_clientdata(clnt);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (md->primary_head) {
123962306a36Sopenharmony_ci		struct matrox_fb_info *minfo = md->primary_head;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci		down_write(&minfo->altout.lock);
124262306a36Sopenharmony_ci		minfo->outputs[1].src = MATROXFB_SRC_NONE;
124362306a36Sopenharmony_ci		minfo->outputs[1].output = NULL;
124462306a36Sopenharmony_ci		minfo->outputs[1].data = NULL;
124562306a36Sopenharmony_ci		minfo->outputs[1].mode = MATROXFB_OUTPUT_MODE_MONITOR;
124662306a36Sopenharmony_ci		up_write(&minfo->altout.lock);
124762306a36Sopenharmony_ci		md->primary_head = NULL;
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci	return 0;
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_cistatic int maven_probe(struct i2c_client *client)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
125562306a36Sopenharmony_ci	int err = -ENODEV;
125662306a36Sopenharmony_ci	struct maven_data* data;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA |
125962306a36Sopenharmony_ci					      I2C_FUNC_SMBUS_BYTE_DATA |
126062306a36Sopenharmony_ci					      I2C_FUNC_NOSTART |
126162306a36Sopenharmony_ci					      I2C_FUNC_PROTOCOL_MANGLING))
126262306a36Sopenharmony_ci		goto ERROR0;
126362306a36Sopenharmony_ci	if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
126462306a36Sopenharmony_ci		err = -ENOMEM;
126562306a36Sopenharmony_ci		goto ERROR0;
126662306a36Sopenharmony_ci	}
126762306a36Sopenharmony_ci	i2c_set_clientdata(client, data);
126862306a36Sopenharmony_ci	err = maven_init_client(client);
126962306a36Sopenharmony_ci	if (err)
127062306a36Sopenharmony_ci		goto ERROR4;
127162306a36Sopenharmony_ci	return 0;
127262306a36Sopenharmony_ciERROR4:;
127362306a36Sopenharmony_ci	kfree(data);
127462306a36Sopenharmony_ciERROR0:;
127562306a36Sopenharmony_ci	return err;
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_cistatic void maven_remove(struct i2c_client *client)
127962306a36Sopenharmony_ci{
128062306a36Sopenharmony_ci	maven_shutdown_client(client);
128162306a36Sopenharmony_ci	kfree(i2c_get_clientdata(client));
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic const struct i2c_device_id maven_id[] = {
128562306a36Sopenharmony_ci	{ "maven", 0 },
128662306a36Sopenharmony_ci	{ }
128762306a36Sopenharmony_ci};
128862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, maven_id);
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_cistatic struct i2c_driver maven_driver={
129162306a36Sopenharmony_ci	.driver = {
129262306a36Sopenharmony_ci		.name	= "maven",
129362306a36Sopenharmony_ci	},
129462306a36Sopenharmony_ci	.probe		= maven_probe,
129562306a36Sopenharmony_ci	.remove		= maven_remove,
129662306a36Sopenharmony_ci	.id_table	= maven_id,
129762306a36Sopenharmony_ci};
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_cimodule_i2c_driver(maven_driver);
130062306a36Sopenharmony_ciMODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
130162306a36Sopenharmony_ciMODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
130262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1303