cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

saa7185.c (9218B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * saa7185 - Philips SAA7185B video encoder driver version 0.0.3
      4 *
      5 * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
      6 *
      7 * Slight changes for video timing and attachment output by
      8 * Wolfgang Scherr <scherr@net4you.net>
      9 *
     10 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
     11 *    - moved over to linux>=2.4.x i2c protocol (1/1/2003)
     12 */
     13
     14#include <linux/module.h>
     15#include <linux/types.h>
     16#include <linux/slab.h>
     17#include <linux/ioctl.h>
     18#include <linux/uaccess.h>
     19#include <linux/i2c.h>
     20#include <linux/videodev2.h>
     21#include <media/v4l2-device.h>
     22
     23MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
     24MODULE_AUTHOR("Dave Perks");
     25MODULE_LICENSE("GPL");
     26
     27static int debug;
     28module_param(debug, int, 0);
     29MODULE_PARM_DESC(debug, "Debug level (0-1)");
     30
     31
     32/* ----------------------------------------------------------------------- */
     33
     34struct saa7185 {
     35	struct v4l2_subdev sd;
     36	unsigned char reg[128];
     37
     38	v4l2_std_id norm;
     39};
     40
     41static inline struct saa7185 *to_saa7185(struct v4l2_subdev *sd)
     42{
     43	return container_of(sd, struct saa7185, sd);
     44}
     45
     46/* ----------------------------------------------------------------------- */
     47
     48static inline int saa7185_read(struct v4l2_subdev *sd)
     49{
     50	struct i2c_client *client = v4l2_get_subdevdata(sd);
     51
     52	return i2c_smbus_read_byte(client);
     53}
     54
     55static int saa7185_write(struct v4l2_subdev *sd, u8 reg, u8 value)
     56{
     57	struct i2c_client *client = v4l2_get_subdevdata(sd);
     58	struct saa7185 *encoder = to_saa7185(sd);
     59
     60	v4l2_dbg(1, debug, sd, "%02x set to %02x\n", reg, value);
     61	encoder->reg[reg] = value;
     62	return i2c_smbus_write_byte_data(client, reg, value);
     63}
     64
     65static int saa7185_write_block(struct v4l2_subdev *sd,
     66		const u8 *data, unsigned int len)
     67{
     68	struct i2c_client *client = v4l2_get_subdevdata(sd);
     69	struct saa7185 *encoder = to_saa7185(sd);
     70	int ret = -1;
     71	u8 reg;
     72
     73	/* the adv7175 has an autoincrement function, use it if
     74	 * the adapter understands raw I2C */
     75	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
     76		/* do raw I2C, not smbus compatible */
     77		u8 block_data[32];
     78		int block_len;
     79
     80		while (len >= 2) {
     81			block_len = 0;
     82			block_data[block_len++] = reg = data[0];
     83			do {
     84				block_data[block_len++] =
     85				    encoder->reg[reg++] = data[1];
     86				len -= 2;
     87				data += 2;
     88			} while (len >= 2 && data[0] == reg && block_len < 32);
     89			ret = i2c_master_send(client, block_data, block_len);
     90			if (ret < 0)
     91				break;
     92		}
     93	} else {
     94		/* do some slow I2C emulation kind of thing */
     95		while (len >= 2) {
     96			reg = *data++;
     97			ret = saa7185_write(sd, reg, *data++);
     98			if (ret < 0)
     99				break;
    100			len -= 2;
    101		}
    102	}
    103
    104	return ret;
    105}
    106
    107/* ----------------------------------------------------------------------- */
    108
    109static const unsigned char init_common[] = {
    110	0x3a, 0x0f,		/* CBENB=0, V656=0, VY2C=1,
    111				 * YUV2C=1, MY2C=1, MUV2C=1 */
    112
    113	0x42, 0x6b,		/* OVLY0=107 */
    114	0x43, 0x00,		/* OVLU0=0     white */
    115	0x44, 0x00,		/* OVLV0=0   */
    116	0x45, 0x22,		/* OVLY1=34  */
    117	0x46, 0xac,		/* OVLU1=172   yellow */
    118	0x47, 0x0e,		/* OVLV1=14  */
    119	0x48, 0x03,		/* OVLY2=3   */
    120	0x49, 0x1d,		/* OVLU2=29    cyan */
    121	0x4a, 0xac,		/* OVLV2=172 */
    122	0x4b, 0xf0,		/* OVLY3=240 */
    123	0x4c, 0xc8,		/* OVLU3=200   green */
    124	0x4d, 0xb9,		/* OVLV3=185 */
    125	0x4e, 0xd4,		/* OVLY4=212 */
    126	0x4f, 0x38,		/* OVLU4=56    magenta */
    127	0x50, 0x47,		/* OVLV4=71  */
    128	0x51, 0xc1,		/* OVLY5=193 */
    129	0x52, 0xe3,		/* OVLU5=227   red */
    130	0x53, 0x54,		/* OVLV5=84  */
    131	0x54, 0xa3,		/* OVLY6=163 */
    132	0x55, 0x54,		/* OVLU6=84    blue */
    133	0x56, 0xf2,		/* OVLV6=242 */
    134	0x57, 0x90,		/* OVLY7=144 */
    135	0x58, 0x00,		/* OVLU7=0     black */
    136	0x59, 0x00,		/* OVLV7=0   */
    137
    138	0x5a, 0x00,		/* CHPS=0    */
    139	0x5b, 0x76,		/* GAINU=118 */
    140	0x5c, 0xa5,		/* GAINV=165 */
    141	0x5d, 0x3c,		/* BLCKL=60  */
    142	0x5e, 0x3a,		/* BLNNL=58  */
    143	0x5f, 0x3a,		/* CCRS=0, BLNVB=58 */
    144	0x60, 0x00,		/* NULL      */
    145
    146	/* 0x61 - 0x66 set according to norm */
    147
    148	0x67, 0x00,		/* 0 : caption 1st byte odd  field */
    149	0x68, 0x00,		/* 0 : caption 2nd byte odd  field */
    150	0x69, 0x00,		/* 0 : caption 1st byte even field */
    151	0x6a, 0x00,		/* 0 : caption 2nd byte even field */
    152
    153	0x6b, 0x91,		/* MODIN=2, PCREF=0, SCCLN=17 */
    154	0x6c, 0x20,		/* SRCV1=0, TRCV2=1, ORCV1=0, PRCV1=0,
    155				 * CBLF=0, ORCV2=0, PRCV2=0 */
    156	0x6d, 0x00,		/* SRCM1=0, CCEN=0 */
    157
    158	0x6e, 0x0e,		/* HTRIG=0x005, approx. centered, at
    159				 * least for PAL */
    160	0x6f, 0x00,		/* HTRIG upper bits */
    161	0x70, 0x20,		/* PHRES=0, SBLN=1, VTRIG=0 */
    162
    163	/* The following should not be needed */
    164
    165	0x71, 0x15,		/* BMRQ=0x115 */
    166	0x72, 0x90,		/* EMRQ=0x690 */
    167	0x73, 0x61,		/* EMRQ=0x690, BMRQ=0x115 */
    168	0x74, 0x00,		/* NULL       */
    169	0x75, 0x00,		/* NULL       */
    170	0x76, 0x00,		/* NULL       */
    171	0x77, 0x15,		/* BRCV=0x115 */
    172	0x78, 0x90,		/* ERCV=0x690 */
    173	0x79, 0x61,		/* ERCV=0x690, BRCV=0x115 */
    174
    175	/* Field length controls */
    176
    177	0x7a, 0x70,		/* FLC=0 */
    178
    179	/* The following should not be needed if SBLN = 1 */
    180
    181	0x7b, 0x16,		/* FAL=22 */
    182	0x7c, 0x35,		/* LAL=244 */
    183	0x7d, 0x20,		/* LAL=244, FAL=22 */
    184};
    185
    186static const unsigned char init_pal[] = {
    187	0x61, 0x1e,		/* FISE=0, PAL=1, SCBW=1, RTCE=1,
    188				 * YGS=1, INPI=0, DOWN=0 */
    189	0x62, 0xc8,		/* DECTYP=1, BSTA=72 */
    190	0x63, 0xcb,		/* FSC0 */
    191	0x64, 0x8a,		/* FSC1 */
    192	0x65, 0x09,		/* FSC2 */
    193	0x66, 0x2a,		/* FSC3 */
    194};
    195
    196static const unsigned char init_ntsc[] = {
    197	0x61, 0x1d,		/* FISE=1, PAL=0, SCBW=1, RTCE=1,
    198				 * YGS=1, INPI=0, DOWN=0 */
    199	0x62, 0xe6,		/* DECTYP=1, BSTA=102 */
    200	0x63, 0x1f,		/* FSC0 */
    201	0x64, 0x7c,		/* FSC1 */
    202	0x65, 0xf0,		/* FSC2 */
    203	0x66, 0x21,		/* FSC3 */
    204};
    205
    206
    207static int saa7185_init(struct v4l2_subdev *sd, u32 val)
    208{
    209	struct saa7185 *encoder = to_saa7185(sd);
    210
    211	saa7185_write_block(sd, init_common, sizeof(init_common));
    212	if (encoder->norm & V4L2_STD_NTSC)
    213		saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
    214	else
    215		saa7185_write_block(sd, init_pal, sizeof(init_pal));
    216	return 0;
    217}
    218
    219static int saa7185_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
    220{
    221	struct saa7185 *encoder = to_saa7185(sd);
    222
    223	if (std & V4L2_STD_NTSC)
    224		saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
    225	else if (std & V4L2_STD_PAL)
    226		saa7185_write_block(sd, init_pal, sizeof(init_pal));
    227	else
    228		return -EINVAL;
    229	encoder->norm = std;
    230	return 0;
    231}
    232
    233static int saa7185_s_routing(struct v4l2_subdev *sd,
    234			     u32 input, u32 output, u32 config)
    235{
    236	struct saa7185 *encoder = to_saa7185(sd);
    237
    238	/* RJ: input = 0: input is from SA7111
    239	 input = 1: input is from ZR36060 */
    240
    241	switch (input) {
    242	case 0:
    243		/* turn off colorbar */
    244		saa7185_write(sd, 0x3a, 0x0f);
    245		/* Switch RTCE to 1 */
    246		saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
    247		saa7185_write(sd, 0x6e, 0x01);
    248		break;
    249
    250	case 1:
    251		/* turn off colorbar */
    252		saa7185_write(sd, 0x3a, 0x0f);
    253		/* Switch RTCE to 0 */
    254		saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00);
    255		/* SW: a slight sync problem... */
    256		saa7185_write(sd, 0x6e, 0x00);
    257		break;
    258
    259	case 2:
    260		/* turn on colorbar */
    261		saa7185_write(sd, 0x3a, 0x8f);
    262		/* Switch RTCE to 0 */
    263		saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
    264		/* SW: a slight sync problem... */
    265		saa7185_write(sd, 0x6e, 0x01);
    266		break;
    267
    268	default:
    269		return -EINVAL;
    270	}
    271	return 0;
    272}
    273
    274/* ----------------------------------------------------------------------- */
    275
    276static const struct v4l2_subdev_core_ops saa7185_core_ops = {
    277	.init = saa7185_init,
    278};
    279
    280static const struct v4l2_subdev_video_ops saa7185_video_ops = {
    281	.s_std_output = saa7185_s_std_output,
    282	.s_routing = saa7185_s_routing,
    283};
    284
    285static const struct v4l2_subdev_ops saa7185_ops = {
    286	.core = &saa7185_core_ops,
    287	.video = &saa7185_video_ops,
    288};
    289
    290
    291/* ----------------------------------------------------------------------- */
    292
    293static int saa7185_probe(struct i2c_client *client,
    294			const struct i2c_device_id *id)
    295{
    296	int i;
    297	struct saa7185 *encoder;
    298	struct v4l2_subdev *sd;
    299
    300	/* Check if the adapter supports the needed features */
    301	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
    302		return -ENODEV;
    303
    304	v4l_info(client, "chip found @ 0x%x (%s)\n",
    305			client->addr << 1, client->adapter->name);
    306
    307	encoder = devm_kzalloc(&client->dev, sizeof(*encoder), GFP_KERNEL);
    308	if (encoder == NULL)
    309		return -ENOMEM;
    310	encoder->norm = V4L2_STD_NTSC;
    311	sd = &encoder->sd;
    312	v4l2_i2c_subdev_init(sd, client, &saa7185_ops);
    313
    314	i = saa7185_write_block(sd, init_common, sizeof(init_common));
    315	if (i >= 0)
    316		i = saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
    317	if (i < 0)
    318		v4l2_dbg(1, debug, sd, "init error %d\n", i);
    319	else
    320		v4l2_dbg(1, debug, sd, "revision 0x%x\n",
    321				saa7185_read(sd) >> 5);
    322	return 0;
    323}
    324
    325static int saa7185_remove(struct i2c_client *client)
    326{
    327	struct v4l2_subdev *sd = i2c_get_clientdata(client);
    328	struct saa7185 *encoder = to_saa7185(sd);
    329
    330	v4l2_device_unregister_subdev(sd);
    331	/* SW: output off is active */
    332	saa7185_write(sd, 0x61, (encoder->reg[0x61]) | 0x40);
    333	return 0;
    334}
    335
    336/* ----------------------------------------------------------------------- */
    337
    338static const struct i2c_device_id saa7185_id[] = {
    339	{ "saa7185", 0 },
    340	{ }
    341};
    342MODULE_DEVICE_TABLE(i2c, saa7185_id);
    343
    344static struct i2c_driver saa7185_driver = {
    345	.driver = {
    346		.name	= "saa7185",
    347	},
    348	.probe		= saa7185_probe,
    349	.remove		= saa7185_remove,
    350	.id_table	= saa7185_id,
    351};
    352
    353module_i2c_driver(saa7185_driver);