]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/media/i2c/bt866.c
Merge branch 'rwsem-optimizations'
[karo-tx-linux.git] / drivers / media / i2c / bt866.c
1 /*
2     bt866 - BT866 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     This code was adapted for the bt866 by Christer Weinigel and ported
14     to 2.6 by Martin Samuelsson.
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>
32 #include <linux/types.h>
33 #include <linux/slab.h>
34 #include <linux/ioctl.h>
35 #include <asm/uaccess.h>
36 #include <linux/i2c.h>
37 #include <linux/videodev2.h>
38 #include <media/v4l2-device.h>
39 #include <media/v4l2-chip-ident.h>
40
41 MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
42 MODULE_AUTHOR("Mike Bernson & Dave Perks");
43 MODULE_LICENSE("GPL");
44
45 static int debug;
46 module_param(debug, int, 0);
47 MODULE_PARM_DESC(debug, "Debug level (0-1)");
48
49
50 /* ----------------------------------------------------------------------- */
51
52 struct bt866 {
53         struct v4l2_subdev sd;
54         u8 reg[256];
55 };
56
57 static inline struct bt866 *to_bt866(struct v4l2_subdev *sd)
58 {
59         return container_of(sd, struct bt866, sd);
60 }
61
62 static int bt866_write(struct bt866 *encoder, u8 subaddr, u8 data)
63 {
64         struct i2c_client *client = v4l2_get_subdevdata(&encoder->sd);
65         u8 buffer[2];
66         int err;
67
68         buffer[0] = subaddr;
69         buffer[1] = data;
70
71         encoder->reg[subaddr] = data;
72
73         v4l_dbg(1, debug, client, "write 0x%02x = 0x%02x\n", subaddr, data);
74
75         for (err = 0; err < 3;) {
76                 if (i2c_master_send(client, buffer, 2) == 2)
77                         break;
78                 err++;
79                 v4l_warn(client, "error #%d writing to 0x%02x\n",
80                                 err, subaddr);
81                 schedule_timeout_interruptible(msecs_to_jiffies(100));
82         }
83         if (err == 3) {
84                 v4l_warn(client, "giving up\n");
85                 return -1;
86         }
87
88         return 0;
89 }
90
91 static int bt866_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
92 {
93         v4l2_dbg(1, debug, sd, "set norm %llx\n", (unsigned long long)std);
94
95         /* Only PAL supported by this driver at the moment! */
96         if (!(std & V4L2_STD_NTSC))
97                 return -EINVAL;
98         return 0;
99 }
100
101 static int bt866_s_routing(struct v4l2_subdev *sd,
102                            u32 input, u32 output, u32 config)
103 {
104         static const __u8 init[] = {
105                 0xc8, 0xcc, /* CRSCALE */
106                 0xca, 0x91, /* CBSCALE */
107                 0xcc, 0x24, /* YC16 | OSDNUM */
108                 0xda, 0x00, /*  */
109                 0xdc, 0x24, /* SETMODE | PAL */
110                 0xde, 0x02, /* EACTIVE */
111
112                 /* overlay colors */
113                 0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
114                 0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
115                 0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
116                 0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
117                 0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
118                 0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
119                 0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
120                 0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
121
122                 0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
123                 0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
124                 0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
125                 0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
126                 0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
127                 0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
128                 0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
129                 0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
130         };
131         struct bt866 *encoder = to_bt866(sd);
132         u8 val;
133         int i;
134
135         for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
136                 bt866_write(encoder, init[i], init[i+1]);
137
138         val = encoder->reg[0xdc];
139
140         if (input == 0)
141                 val |= 0x40; /* CBSWAP */
142         else
143                 val &= ~0x40; /* !CBSWAP */
144
145         bt866_write(encoder, 0xdc, val);
146
147         val = encoder->reg[0xcc];
148         if (input == 2)
149                 val |= 0x01; /* OSDBAR */
150         else
151                 val &= ~0x01; /* !OSDBAR */
152         bt866_write(encoder, 0xcc, val);
153
154         v4l2_dbg(1, debug, sd, "set input %d\n", input);
155
156         switch (input) {
157         case 0:
158         case 1:
159         case 2:
160                 break;
161         default:
162                 return -EINVAL;
163         }
164         return 0;
165 }
166
167 #if 0
168 /* Code to setup square pixels, might be of some use in the future,
169    but is currently unused. */
170         val = encoder->reg[0xdc];
171         if (*iarg)
172                 val |= 1; /* SQUARE */
173         else
174                 val &= ~1; /* !SQUARE */
175         bt866_write(client, 0xdc, val);
176 #endif
177
178 static int bt866_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
179 {
180         struct i2c_client *client = v4l2_get_subdevdata(sd);
181
182         return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_BT866, 0);
183 }
184
185 /* ----------------------------------------------------------------------- */
186
187 static const struct v4l2_subdev_core_ops bt866_core_ops = {
188         .g_chip_ident = bt866_g_chip_ident,
189 };
190
191 static const struct v4l2_subdev_video_ops bt866_video_ops = {
192         .s_std_output = bt866_s_std_output,
193         .s_routing = bt866_s_routing,
194 };
195
196 static const struct v4l2_subdev_ops bt866_ops = {
197         .core = &bt866_core_ops,
198         .video = &bt866_video_ops,
199 };
200
201 static int bt866_probe(struct i2c_client *client,
202                         const struct i2c_device_id *id)
203 {
204         struct bt866 *encoder;
205         struct v4l2_subdev *sd;
206
207         v4l_info(client, "chip found @ 0x%x (%s)\n",
208                         client->addr << 1, client->adapter->name);
209
210         encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
211         if (encoder == NULL)
212                 return -ENOMEM;
213         sd = &encoder->sd;
214         v4l2_i2c_subdev_init(sd, client, &bt866_ops);
215         return 0;
216 }
217
218 static int bt866_remove(struct i2c_client *client)
219 {
220         struct v4l2_subdev *sd = i2c_get_clientdata(client);
221
222         v4l2_device_unregister_subdev(sd);
223         kfree(to_bt866(sd));
224         return 0;
225 }
226
227 static const struct i2c_device_id bt866_id[] = {
228         { "bt866", 0 },
229         { }
230 };
231 MODULE_DEVICE_TABLE(i2c, bt866_id);
232
233 static struct i2c_driver bt866_driver = {
234         .driver = {
235                 .owner  = THIS_MODULE,
236                 .name   = "bt866",
237         },
238         .probe          = bt866_probe,
239         .remove         = bt866_remove,
240         .id_table       = bt866_id,
241 };
242
243 module_i2c_driver(bt866_driver);