blob: 3e042c5ddaa7ffa46f50414207087e707b9a7664 [file] [log] [blame]
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * bt856 - BT856A Digital Video Encoder (Rockwell Part)
3 *
4 * Copyright (C) 1999 Mike Bernson <mike@mlb.org>
5 * Copyright (C) 1998 Dave Perks <dperks@ibm.net>
6 *
7 * Modifications for LML33/DC10plus unified driver
8 * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
9 *
10 * This code was modify/ported from the saa7111 driver written
11 * by Dave Perks.
12 *
13 * Changes by Ronald Bultje <rbultje@ronald.bitfreak.net>
14 * - moved over to linux>=2.4.x i2c protocol (9/9/2002)
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 */
30
31#include <linux/module.h>
Mauro Carvalho Chehab18f3fa12007-07-02 15:39:57 -030032#include <linux/types.h>
Hans Verkuila8c26df2008-09-07 07:59:35 -030033#include <linux/ioctl.h>
Mauro Carvalho Chehab18f3fa12007-07-02 15:39:57 -030034#include <asm/uaccess.h>
Hans Verkuila8c26df2008-09-07 07:59:35 -030035#include <linux/i2c.h>
36#include <linux/i2c-id.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/videodev.h>
Hans Verkuila8c26df2008-09-07 07:59:35 -030038#include <linux/video_encoder.h>
39#include <media/v4l2-common.h>
40#include <media/v4l2-i2c-drv-legacy.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
43MODULE_AUTHOR("Mike Bernson & Dave Perks");
44MODULE_LICENSE("GPL");
45
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030046static int debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047module_param(debug, int, 0);
48MODULE_PARM_DESC(debug, "Debug level (0-1)");
49
Linus Torvalds1da177e2005-04-16 15:20:36 -070050/* ----------------------------------------------------------------------- */
51
Hans Verkuil187565c2008-08-30 06:03:09 -030052#define BT856_REG_OFFSET 0xDA
53#define BT856_NR_REG 6
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
55struct bt856 {
Jean Delvaref49a5ea2006-03-22 03:48:36 -030056 unsigned char reg[BT856_NR_REG];
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Hans Verkuil107063c2009-02-18 17:26:06 -030058 v4l2_std_id norm;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059};
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061/* ----------------------------------------------------------------------- */
62
Hans Verkuila8c26df2008-09-07 07:59:35 -030063static inline int bt856_write(struct i2c_client *client, u8 reg, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070064{
65 struct bt856 *encoder = i2c_get_clientdata(client);
66
Hans Verkuil187565c2008-08-30 06:03:09 -030067 encoder->reg[reg - BT856_REG_OFFSET] = value;
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 return i2c_smbus_write_byte_data(client, reg, value);
69}
70
Hans Verkuila8c26df2008-09-07 07:59:35 -030071static inline int bt856_setbit(struct i2c_client *client, u8 reg, u8 bit, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070072{
73 struct bt856 *encoder = i2c_get_clientdata(client);
74
75 return bt856_write(client, reg,
Hans Verkuila8c26df2008-09-07 07:59:35 -030076 (encoder->reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) |
77 (value ? (1 << bit) : 0));
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
Hans Verkuila8c26df2008-09-07 07:59:35 -030080static void bt856_dump(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -070081{
82 int i;
83 struct bt856 *encoder = i2c_get_clientdata(client);
84
Hans Verkuila8c26df2008-09-07 07:59:35 -030085 v4l_info(client, "register dump:\n");
Jean Delvaref49a5ea2006-03-22 03:48:36 -030086 for (i = 0; i < BT856_NR_REG; i += 2)
Hans Verkuila8c26df2008-09-07 07:59:35 -030087 printk(KERN_CONT " %02x", encoder->reg[i]);
88 printk(KERN_CONT "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070089}
90
91/* ----------------------------------------------------------------------- */
92
Hans Verkuila8c26df2008-09-07 07:59:35 -030093static int bt856_command(struct i2c_client *client, unsigned cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
95 struct bt856 *encoder = i2c_get_clientdata(client);
96
97 switch (cmd) {
Hans Verkuil107063c2009-02-18 17:26:06 -030098 case VIDIOC_INT_INIT:
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 /* This is just for testing!!! */
Hans Verkuila8c26df2008-09-07 07:59:35 -0300100 v4l_dbg(1, debug, client, "init\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 bt856_write(client, 0xdc, 0x18);
102 bt856_write(client, 0xda, 0);
103 bt856_write(client, 0xde, 0);
104
105 bt856_setbit(client, 0xdc, 3, 1);
106 //bt856_setbit(client, 0xdc, 6, 0);
107 bt856_setbit(client, 0xdc, 4, 1);
108
Hans Verkuil107063c2009-02-18 17:26:06 -0300109 if (encoder->norm & V4L2_STD_NTSC)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 bt856_setbit(client, 0xdc, 2, 0);
Hans Verkuil107063c2009-02-18 17:26:06 -0300111 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 bt856_setbit(client, 0xdc, 2, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
114 bt856_setbit(client, 0xdc, 1, 1);
115 bt856_setbit(client, 0xde, 4, 0);
116 bt856_setbit(client, 0xde, 3, 1);
117 if (debug != 0)
118 bt856_dump(client);
119 break;
120
Hans Verkuil107063c2009-02-18 17:26:06 -0300121 case VIDIOC_INT_S_STD_OUTPUT:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 {
Hans Verkuil107063c2009-02-18 17:26:06 -0300123 v4l2_std_id *iarg = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Hans Verkuil107063c2009-02-18 17:26:06 -0300125 v4l_dbg(1, debug, client, "set norm %llx\n", *iarg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
Hans Verkuil107063c2009-02-18 17:26:06 -0300127 if (*iarg & V4L2_STD_NTSC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 bt856_setbit(client, 0xdc, 2, 0);
Hans Verkuil107063c2009-02-18 17:26:06 -0300129 } else if (*iarg & V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 bt856_setbit(client, 0xdc, 2, 1);
131 bt856_setbit(client, 0xda, 0, 0);
132 //bt856_setbit(client, 0xda, 0, 1);
Hans Verkuil107063c2009-02-18 17:26:06 -0300133 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 }
136 encoder->norm = *iarg;
137 if (debug != 0)
138 bt856_dump(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 break;
Hans Verkuila8c26df2008-09-07 07:59:35 -0300140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Hans Verkuil107063c2009-02-18 17:26:06 -0300142 case VIDIOC_INT_S_VIDEO_ROUTING:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 {
Hans Verkuil107063c2009-02-18 17:26:06 -0300144 struct v4l2_routing *route = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Hans Verkuil107063c2009-02-18 17:26:06 -0300146 v4l_dbg(1, debug, client, "set input %d\n", route->input);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148 /* We only have video bus.
Hans Verkuil107063c2009-02-18 17:26:06 -0300149 * route->input= 0: input is from bt819
150 * route->input= 1: input is from ZR36060 */
151 switch (route->input) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 case 0:
153 bt856_setbit(client, 0xde, 4, 0);
154 bt856_setbit(client, 0xde, 3, 1);
155 bt856_setbit(client, 0xdc, 3, 1);
156 bt856_setbit(client, 0xdc, 6, 0);
157 break;
158 case 1:
159 bt856_setbit(client, 0xde, 4, 0);
160 bt856_setbit(client, 0xde, 3, 1);
161 bt856_setbit(client, 0xdc, 3, 1);
162 bt856_setbit(client, 0xdc, 6, 1);
163 break;
164 case 2: // Color bar
165 bt856_setbit(client, 0xdc, 3, 0);
166 bt856_setbit(client, 0xde, 4, 1);
167 break;
168 default:
169 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 }
171
172 if (debug != 0)
173 bt856_dump(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 break;
Hans Verkuila8c26df2008-09-07 07:59:35 -0300175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 default:
178 return -EINVAL;
179 }
180
181 return 0;
182}
183
184/* ----------------------------------------------------------------------- */
185
Hans Verkuila8c26df2008-09-07 07:59:35 -0300186static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Hans Verkuila8c26df2008-09-07 07:59:35 -0300188I2C_CLIENT_INSMOD;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300189
Hans Verkuila8c26df2008-09-07 07:59:35 -0300190static int bt856_probe(struct i2c_client *client,
191 const struct i2c_device_id *id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 struct bt856 *encoder;
194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 /* Check if the adapter supports the needed features */
Hans Verkuila8c26df2008-09-07 07:59:35 -0300196 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
197 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Hans Verkuila8c26df2008-09-07 07:59:35 -0300199 v4l_info(client, "chip found @ 0x%x (%s)\n",
200 client->addr << 1, client->adapter->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Panagiotis Issaris74081872006-01-11 19:40:56 -0200202 encoder = kzalloc(sizeof(struct bt856), GFP_KERNEL);
Hans Verkuila8c26df2008-09-07 07:59:35 -0300203 if (encoder == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 return -ENOMEM;
Hans Verkuil107063c2009-02-18 17:26:06 -0300205 encoder->norm = V4L2_STD_NTSC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 i2c_set_clientdata(client, encoder);
207
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 bt856_write(client, 0xdc, 0x18);
209 bt856_write(client, 0xda, 0);
210 bt856_write(client, 0xde, 0);
211
212 bt856_setbit(client, 0xdc, 3, 1);
213 //bt856_setbit(client, 0xdc, 6, 0);
214 bt856_setbit(client, 0xdc, 4, 1);
215
Hans Verkuil107063c2009-02-18 17:26:06 -0300216 if (encoder->norm & V4L2_STD_NTSC)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 bt856_setbit(client, 0xdc, 2, 0);
Hans Verkuil107063c2009-02-18 17:26:06 -0300218 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 bt856_setbit(client, 0xdc, 2, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221 bt856_setbit(client, 0xdc, 1, 1);
222 bt856_setbit(client, 0xde, 4, 0);
223 bt856_setbit(client, 0xde, 3, 1);
224
225 if (debug != 0)
226 bt856_dump(client);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 return 0;
228}
229
Hans Verkuila8c26df2008-09-07 07:59:35 -0300230static int bt856_remove(struct i2c_client *client)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Hans Verkuila8c26df2008-09-07 07:59:35 -0300232 kfree(i2c_get_clientdata(client));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 return 0;
234}
235
Hans Verkuila8c26df2008-09-07 07:59:35 -0300236static const struct i2c_device_id bt856_id[] = {
237 { "bt856", 0 },
238 { }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239};
Hans Verkuila8c26df2008-09-07 07:59:35 -0300240MODULE_DEVICE_TABLE(i2c, bt856_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
Hans Verkuila8c26df2008-09-07 07:59:35 -0300242static struct v4l2_i2c_driver_data v4l2_i2c_data = {
243 .name = "bt856",
244 .driverid = I2C_DRIVERID_BT856,
245 .command = bt856_command,
246 .probe = bt856_probe,
247 .remove = bt856_remove,
248 .id_table = bt856_id,
249};