brintos

brintos / linux-shallow public Read only

0
0
Text · 14.2 KiB · a155b98 Raw
629 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2008 Sensoray Company Inc.4 */5 6#include <linux/module.h>7#include <linux/usb.h>8#include <linux/i2c.h>9#include <linux/videodev2.h>10#include <linux/slab.h>11#include <media/v4l2-device.h>12#include <media/v4l2-common.h>13#include <media/v4l2-subdev.h>14#include "go7007-priv.h"15 16MODULE_DESCRIPTION("Sensoray 2250/2251 i2c v4l2 subdev driver");17MODULE_LICENSE("GPL v2");18 19/*20 * Note: this board has two i2c devices: a vpx3226f and a tlv320aic23b.21 * Due to the unusual way these are accessed on this device we do not22 * reuse the i2c drivers, but instead they are implemented in this23 * driver. It would be nice to improve on this, though.24 */25 26#define TLV320_ADDRESS      0x3427#define VPX322_ADDR_ANALOGCONTROL1	0x0228#define VPX322_ADDR_BRIGHTNESS0		0x012729#define VPX322_ADDR_BRIGHTNESS1		0x013130#define VPX322_ADDR_CONTRAST0		0x012831#define VPX322_ADDR_CONTRAST1		0x013232#define VPX322_ADDR_HUE			0x00dc33#define VPX322_ADDR_SAT			0x003034 35struct go7007_usb_board {36	unsigned int flags;37	struct go7007_board_info main_info;38};39 40struct go7007_usb {41	struct go7007_usb_board *board;42	struct mutex i2c_lock;43	struct usb_device *usbdev;44	struct urb *video_urbs[8];45	struct urb *audio_urbs[8];46	struct urb *intr_urb;47};48 49static unsigned char aud_regs[] = {50	0x1e, 0x00,51	0x00, 0x17,52	0x02, 0x17,53	0x04, 0xf9,54	0x06, 0xf9,55	0x08, 0x02,56	0x0a, 0x00,57	0x0c, 0x00,58	0x0a, 0x00,59	0x0c, 0x00,60	0x0e, 0x02,61	0x10, 0x00,62	0x12, 0x01,63	0x00, 0x00,64};65 66 67static unsigned char vid_regs[] = {68	0xF2, 0x0f,69	0xAA, 0x00,70	0xF8, 0xff,71	0x00, 0x00,72};73 74static u16 vid_regs_fp[] = {75	0x028, 0x067,76	0x120, 0x016,77	0x121, 0xcF2,78	0x122, 0x0F2,79	0x123, 0x00c,80	0x124, 0x2d0,81	0x125, 0x2e0,82	0x126, 0x004,83	0x128, 0x1E0,84	0x12A, 0x016,85	0x12B, 0x0F2,86	0x12C, 0x0F2,87	0x12D, 0x00c,88	0x12E, 0x2d0,89	0x12F, 0x2e0,90	0x130, 0x004,91	0x132, 0x1E0,92	0x140, 0x060,93	0x153, 0x00C,94	0x154, 0x200,95	0x150, 0x801,96	0x000, 0x00097};98 99/* PAL specific values */100static u16 vid_regs_fp_pal[] = {101	0x120, 0x017,102	0x121, 0xd22,103	0x122, 0x122,104	0x12A, 0x017,105	0x12B, 0x122,106	0x12C, 0x122,107	0x140, 0x060,108	0x000, 0x000,109};110 111struct s2250 {112	struct v4l2_subdev sd;113	struct v4l2_ctrl_handler hdl;114	v4l2_std_id std;115	int input;116	int brightness;117	int contrast;118	int saturation;119	int hue;120	int reg12b_val;121	int audio_input;122	struct i2c_client *audio;123};124 125static inline struct s2250 *to_state(struct v4l2_subdev *sd)126{127	return container_of(sd, struct s2250, sd);128}129 130/* from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/131static int go7007_usb_vendor_request(struct go7007 *go, u16 request,132	u16 value, u16 index, void *transfer_buffer, int length, int in)133{134	struct go7007_usb *usb = go->hpi_context;135	int timeout = 5000;136 137	if (in) {138		return usb_control_msg(usb->usbdev,139				usb_rcvctrlpipe(usb->usbdev, 0), request,140				USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,141				value, index, transfer_buffer, length, timeout);142	} else {143		return usb_control_msg(usb->usbdev,144				usb_sndctrlpipe(usb->usbdev, 0), request,145				USB_TYPE_VENDOR | USB_RECIP_DEVICE,146				value, index, transfer_buffer, length, timeout);147	}148}149/* end from go7007-usb.c which is Copyright (C) 2005-2006 Micronas USA Inc.*/150 151static int write_reg(struct i2c_client *client, u8 reg, u8 value)152{153	struct go7007 *go = i2c_get_adapdata(client->adapter);154	struct go7007_usb *usb;155	int rc;156	int dev_addr = client->addr << 1;  /* firmware wants 8-bit address */157	u8 *buf;158 159	if (go == NULL)160		return -ENODEV;161 162	if (go->status == STATUS_SHUTDOWN)163		return -EBUSY;164 165	buf = kzalloc(16, GFP_KERNEL);166	if (buf == NULL)167		return -ENOMEM;168 169	usb = go->hpi_context;170	if (mutex_lock_interruptible(&usb->i2c_lock) != 0) {171		dev_info(&client->dev, "i2c lock failed\n");172		kfree(buf);173		return -EINTR;174	}175	rc = go7007_usb_vendor_request(go, 0x55, dev_addr,176				       (reg<<8 | value),177				       buf,178				       16, 1);179 180	mutex_unlock(&usb->i2c_lock);181	kfree(buf);182	return rc;183}184 185static int write_reg_fp(struct i2c_client *client, u16 addr, u16 val)186{187	struct go7007 *go = i2c_get_adapdata(client->adapter);188	struct go7007_usb *usb;189	int rc;190	u8 *buf;191	struct s2250 *dec = i2c_get_clientdata(client);192 193	if (go == NULL)194		return -ENODEV;195 196	if (go->status == STATUS_SHUTDOWN)197		return -EBUSY;198 199	buf = kzalloc(16, GFP_KERNEL);200 201	if (buf == NULL)202		return -ENOMEM;203 204 205 206	memset(buf, 0xcd, 6);207 208	usb = go->hpi_context;209	if (mutex_lock_interruptible(&usb->i2c_lock) != 0) {210		dev_info(&client->dev, "i2c lock failed\n");211		kfree(buf);212		return -EINTR;213	}214	rc = go7007_usb_vendor_request(go, 0x57, addr, val, buf, 16, 1);215	mutex_unlock(&usb->i2c_lock);216	if (rc < 0) {217		kfree(buf);218		return rc;219	}220 221	if (buf[0] == 0) {222		unsigned int subaddr, val_read;223 224		subaddr = (buf[4] << 8) + buf[5];225		val_read = (buf[2] << 8) + buf[3];226		kfree(buf);227		if (val_read != val) {228			dev_info(&client->dev, "invalid fp write %x %x\n",229				 val_read, val);230			return -EFAULT;231		}232		if (subaddr != addr) {233			dev_info(&client->dev, "invalid fp write addr %x %x\n",234				 subaddr, addr);235			return -EFAULT;236		}237	} else {238		kfree(buf);239		return -EFAULT;240	}241 242	/* save last 12b value */243	if (addr == 0x12b)244		dec->reg12b_val = val;245 246	return 0;247}248 249static int read_reg_fp(struct i2c_client *client, u16 addr, u16 *val)250{251	struct go7007 *go = i2c_get_adapdata(client->adapter);252	struct go7007_usb *usb;253	int rc;254	u8 *buf;255 256	if (go == NULL)257		return -ENODEV;258 259	if (go->status == STATUS_SHUTDOWN)260		return -EBUSY;261 262	buf = kzalloc(16, GFP_KERNEL);263 264	if (buf == NULL)265		return -ENOMEM;266 267 268 269	memset(buf, 0xcd, 6);270	usb = go->hpi_context;271	if (mutex_lock_interruptible(&usb->i2c_lock) != 0) {272		dev_info(&client->dev, "i2c lock failed\n");273		kfree(buf);274		return -EINTR;275	}276	rc = go7007_usb_vendor_request(go, 0x58, addr, 0, buf, 16, 1);277	mutex_unlock(&usb->i2c_lock);278	if (rc < 0) {279		kfree(buf);280		return rc;281	}282 283	*val = (buf[0] << 8) | buf[1];284	kfree(buf);285 286	return 0;287}288 289 290static int write_regs(struct i2c_client *client, u8 *regs)291{292	int i;293 294	for (i = 0; !((regs[i] == 0x00) && (regs[i+1] == 0x00)); i += 2) {295		if (write_reg(client, regs[i], regs[i+1]) < 0) {296			dev_info(&client->dev, "failed\n");297			return -1;298		}299	}300	return 0;301}302 303static int write_regs_fp(struct i2c_client *client, u16 *regs)304{305	int i;306 307	for (i = 0; !((regs[i] == 0x00) && (regs[i+1] == 0x00)); i += 2) {308		if (write_reg_fp(client, regs[i], regs[i+1]) < 0) {309			dev_info(&client->dev, "failed fp\n");310			return -1;311		}312	}313	return 0;314}315 316 317/* ------------------------------------------------------------------------- */318 319static int s2250_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output,320				 u32 config)321{322	struct s2250 *state = to_state(sd);323	struct i2c_client *client = v4l2_get_subdevdata(sd);324	int vidsys;325 326	vidsys = (state->std == V4L2_STD_NTSC) ? 0x01 : 0x00;327	if (input == 0) {328		/* composite */329		write_reg_fp(client, 0x20, 0x020 | vidsys);330		write_reg_fp(client, 0x21, 0x662);331		write_reg_fp(client, 0x140, 0x060);332	} else if (input == 1) {333		/* S-Video */334		write_reg_fp(client, 0x20, 0x040 | vidsys);335		write_reg_fp(client, 0x21, 0x666);336		write_reg_fp(client, 0x140, 0x060);337	} else {338		return -EINVAL;339	}340	state->input = input;341	return 0;342}343 344static int s2250_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)345{346	struct s2250 *state = to_state(sd);347	struct i2c_client *client = v4l2_get_subdevdata(sd);348	u16 vidsource;349 350	vidsource = (state->input == 1) ? 0x040 : 0x020;351	if (norm & V4L2_STD_625_50) {352		write_regs_fp(client, vid_regs_fp);353		write_regs_fp(client, vid_regs_fp_pal);354		write_reg_fp(client, 0x20, vidsource);355	} else {356		write_regs_fp(client, vid_regs_fp);357		write_reg_fp(client, 0x20, vidsource | 1);358	}359	state->std = norm;360	return 0;361}362 363static int s2250_s_ctrl(struct v4l2_ctrl *ctrl)364{365	struct s2250 *state = container_of(ctrl->handler, struct s2250, hdl);366	struct i2c_client *client = v4l2_get_subdevdata(&state->sd);367	u16 oldvalue;368 369	switch (ctrl->id) {370	case V4L2_CID_BRIGHTNESS:371		read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue);372		write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0,373			     ctrl->val | (oldvalue & ~0xff));374		read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue);375		write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1,376			     ctrl->val | (oldvalue & ~0xff));377		write_reg_fp(client, 0x140, 0x60);378		break;379	case V4L2_CID_CONTRAST:380		read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue);381		write_reg_fp(client, VPX322_ADDR_CONTRAST0,382			     ctrl->val | (oldvalue & ~0x3f));383		read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue);384		write_reg_fp(client, VPX322_ADDR_CONTRAST1,385			     ctrl->val | (oldvalue & ~0x3f));386		write_reg_fp(client, 0x140, 0x60);387		break;388	case V4L2_CID_SATURATION:389		write_reg_fp(client, VPX322_ADDR_SAT, ctrl->val);390		break;391	case V4L2_CID_HUE:392		write_reg_fp(client, VPX322_ADDR_HUE, ctrl->val);393		break;394	default:395		return -EINVAL;396	}397	return 0;398}399 400static int s2250_set_fmt(struct v4l2_subdev *sd,401		struct v4l2_subdev_state *sd_state,402		struct v4l2_subdev_format *format)403{404	struct v4l2_mbus_framefmt *fmt = &format->format;405	struct s2250 *state = to_state(sd);406	struct i2c_client *client = v4l2_get_subdevdata(sd);407 408	if (format->pad)409		return -EINVAL;410 411	if (format->which == V4L2_SUBDEV_FORMAT_TRY)412		return 0;413 414	if (fmt->height < 640) {415		write_reg_fp(client, 0x12b, state->reg12b_val | 0x400);416		write_reg_fp(client, 0x140, 0x060);417	} else {418		write_reg_fp(client, 0x12b, state->reg12b_val & ~0x400);419		write_reg_fp(client, 0x140, 0x060);420	}421	return 0;422}423 424static int s2250_s_audio_routing(struct v4l2_subdev *sd, u32 input, u32 output,425				 u32 config)426{427	struct s2250 *state = to_state(sd);428 429	switch (input) {430	case 0:431		write_reg(state->audio, 0x08, 0x02); /* Line In */432		break;433	case 1:434		write_reg(state->audio, 0x08, 0x04); /* Mic */435		break;436	case 2:437		write_reg(state->audio, 0x08, 0x05); /* Mic Boost */438		break;439	default:440		return -EINVAL;441	}442	state->audio_input = input;443	return 0;444}445 446 447static int s2250_log_status(struct v4l2_subdev *sd)448{449	struct s2250 *state = to_state(sd);450 451	v4l2_info(sd, "Standard: %s\n", state->std == V4L2_STD_NTSC ? "NTSC" :452					state->std == V4L2_STD_PAL ? "PAL" :453					state->std == V4L2_STD_SECAM ? "SECAM" :454					"unknown");455	v4l2_info(sd, "Input: %s\n", state->input == 0 ? "Composite" :456					state->input == 1 ? "S-video" :457					"error");458	v4l2_info(sd, "Audio input: %s\n", state->audio_input == 0 ? "Line In" :459					state->audio_input == 1 ? "Mic" :460					state->audio_input == 2 ? "Mic Boost" :461					"error");462	return v4l2_ctrl_subdev_log_status(sd);463}464 465/* --------------------------------------------------------------------------*/466 467static const struct v4l2_ctrl_ops s2250_ctrl_ops = {468	.s_ctrl = s2250_s_ctrl,469};470 471static const struct v4l2_subdev_core_ops s2250_core_ops = {472	.log_status = s2250_log_status,473};474 475static const struct v4l2_subdev_audio_ops s2250_audio_ops = {476	.s_routing = s2250_s_audio_routing,477};478 479static const struct v4l2_subdev_video_ops s2250_video_ops = {480	.s_std = s2250_s_std,481	.s_routing = s2250_s_video_routing,482};483 484static const struct v4l2_subdev_pad_ops s2250_pad_ops = {485	.set_fmt = s2250_set_fmt,486};487 488static const struct v4l2_subdev_ops s2250_ops = {489	.core = &s2250_core_ops,490	.audio = &s2250_audio_ops,491	.video = &s2250_video_ops,492	.pad = &s2250_pad_ops,493};494 495/* --------------------------------------------------------------------------*/496 497static int s2250_probe(struct i2c_client *client)498{499	struct i2c_client *audio;500	struct i2c_adapter *adapter = client->adapter;501	struct s2250 *state;502	struct v4l2_subdev *sd;503	u8 *data;504	struct go7007 *go = i2c_get_adapdata(adapter);505	struct go7007_usb *usb = go->hpi_context;506	int err = -EIO;507 508	audio = i2c_new_dummy_device(adapter, TLV320_ADDRESS >> 1);509	if (IS_ERR(audio))510		return PTR_ERR(audio);511 512	state = kzalloc(sizeof(struct s2250), GFP_KERNEL);513	if (state == NULL) {514		i2c_unregister_device(audio);515		return -ENOMEM;516	}517 518	sd = &state->sd;519	v4l2_i2c_subdev_init(sd, client, &s2250_ops);520 521	v4l2_info(sd, "initializing %s at address 0x%x on %s\n",522	       "Sensoray 2250/2251", client->addr, client->adapter->name);523 524	v4l2_ctrl_handler_init(&state->hdl, 4);525	v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops,526		V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);527	v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops,528		V4L2_CID_CONTRAST, 0, 0x3f, 1, 0x32);529	v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops,530		V4L2_CID_SATURATION, 0, 4094, 1, 2070);531	v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops,532		V4L2_CID_HUE, -512, 511, 1, 0);533	sd->ctrl_handler = &state->hdl;534	if (state->hdl.error) {535		err = state->hdl.error;536		goto fail;537	}538 539	state->std = V4L2_STD_NTSC;540	state->brightness = 50;541	state->contrast = 50;542	state->saturation = 50;543	state->hue = 0;544	state->audio = audio;545 546	/* initialize the audio */547	if (write_regs(audio, aud_regs) < 0) {548		dev_err(&client->dev, "error initializing audio\n");549		goto fail;550	}551 552	if (write_regs(client, vid_regs) < 0) {553		dev_err(&client->dev, "error initializing decoder\n");554		goto fail;555	}556	if (write_regs_fp(client, vid_regs_fp) < 0) {557		dev_err(&client->dev, "error initializing decoder\n");558		goto fail;559	}560	/* set default channel */561	/* composite */562	write_reg_fp(client, 0x20, 0x020 | 1);563	write_reg_fp(client, 0x21, 0x662);564	write_reg_fp(client, 0x140, 0x060);565 566	/* set default audio input */567	state->audio_input = 0;568	write_reg(client, 0x08, 0x02); /* Line In */569 570	if (mutex_lock_interruptible(&usb->i2c_lock) == 0) {571		data = kzalloc(16, GFP_KERNEL);572		if (data != NULL) {573			int rc = go7007_usb_vendor_request(go, 0x41, 0, 0,574						       data, 16, 1);575 576			if (rc > 0) {577				u8 mask;578 579				data[0] = 0;580				mask = 1<<5;581				data[0] &= ~mask;582				data[1] |= mask;583				go7007_usb_vendor_request(go, 0x40, 0,584							  (data[1]<<8)585							  + data[1],586							  data, 16, 0);587			}588			kfree(data);589		}590		mutex_unlock(&usb->i2c_lock);591	}592 593	v4l2_info(sd, "initialized successfully\n");594	return 0;595 596fail:597	i2c_unregister_device(audio);598	v4l2_ctrl_handler_free(&state->hdl);599	kfree(state);600	return err;601}602 603static void s2250_remove(struct i2c_client *client)604{605	struct s2250 *state = to_state(i2c_get_clientdata(client));606 607	i2c_unregister_device(state->audio);608	v4l2_device_unregister_subdev(&state->sd);609	v4l2_ctrl_handler_free(&state->hdl);610	kfree(state);611}612 613static const struct i2c_device_id s2250_id[] = {614	{ "s2250" },615	{ }616};617MODULE_DEVICE_TABLE(i2c, s2250_id);618 619static struct i2c_driver s2250_driver = {620	.driver = {621		.name	= "s2250",622	},623	.probe		= s2250_probe,624	.remove		= s2250_remove,625	.id_table	= s2250_id,626};627 628module_i2c_driver(s2250_driver);629