1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <linux/module.h>
28#include <linux/types.h>
29#include <linux/slab.h>
30#include <linux/ioctl.h>
31#include <asm/uaccess.h>
32#include <linux/i2c.h>
33#include <linux/videodev2.h>
34#include <media/v4l2-device.h>
35#include <media/v4l2-chip-ident.h>
36
37MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
38MODULE_AUTHOR("Dave Perks");
39MODULE_LICENSE("GPL");
40
41static int debug;
42module_param(debug, int, 0);
43MODULE_PARM_DESC(debug, "Debug level (0-1)");
44
45
46
47
48struct saa7185 {
49 struct v4l2_subdev sd;
50 unsigned char reg[128];
51
52 v4l2_std_id norm;
53};
54
55static inline struct saa7185 *to_saa7185(struct v4l2_subdev *sd)
56{
57 return container_of(sd, struct saa7185, sd);
58}
59
60
61
62static inline int saa7185_read(struct v4l2_subdev *sd)
63{
64 struct i2c_client *client = v4l2_get_subdevdata(sd);
65
66 return i2c_smbus_read_byte(client);
67}
68
69static int saa7185_write(struct v4l2_subdev *sd, u8 reg, u8 value)
70{
71 struct i2c_client *client = v4l2_get_subdevdata(sd);
72 struct saa7185 *encoder = to_saa7185(sd);
73
74 v4l2_dbg(1, debug, sd, "%02x set to %02x\n", reg, value);
75 encoder->reg[reg] = value;
76 return i2c_smbus_write_byte_data(client, reg, value);
77}
78
79static int saa7185_write_block(struct v4l2_subdev *sd,
80 const u8 *data, unsigned int len)
81{
82 struct i2c_client *client = v4l2_get_subdevdata(sd);
83 struct saa7185 *encoder = to_saa7185(sd);
84 int ret = -1;
85 u8 reg;
86
87
88
89 if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
90
91 u8 block_data[32];
92 int block_len;
93
94 while (len >= 2) {
95 block_len = 0;
96 block_data[block_len++] = reg = data[0];
97 do {
98 block_data[block_len++] =
99 encoder->reg[reg++] = data[1];
100 len -= 2;
101 data += 2;
102 } while (len >= 2 && data[0] == reg && block_len < 32);
103 ret = i2c_master_send(client, block_data, block_len);
104 if (ret < 0)
105 break;
106 }
107 } else {
108
109 while (len >= 2) {
110 reg = *data++;
111 ret = saa7185_write(sd, reg, *data++);
112 if (ret < 0)
113 break;
114 len -= 2;
115 }
116 }
117
118 return ret;
119}
120
121
122
123static const unsigned char init_common[] = {
124 0x3a, 0x0f,
125
126
127 0x42, 0x6b,
128 0x43, 0x00,
129 0x44, 0x00,
130 0x45, 0x22,
131 0x46, 0xac,
132 0x47, 0x0e,
133 0x48, 0x03,
134 0x49, 0x1d,
135 0x4a, 0xac,
136 0x4b, 0xf0,
137 0x4c, 0xc8,
138 0x4d, 0xb9,
139 0x4e, 0xd4,
140 0x4f, 0x38,
141 0x50, 0x47,
142 0x51, 0xc1,
143 0x52, 0xe3,
144 0x53, 0x54,
145 0x54, 0xa3,
146 0x55, 0x54,
147 0x56, 0xf2,
148 0x57, 0x90,
149 0x58, 0x00,
150 0x59, 0x00,
151
152 0x5a, 0x00,
153 0x5b, 0x76,
154 0x5c, 0xa5,
155 0x5d, 0x3c,
156 0x5e, 0x3a,
157 0x5f, 0x3a,
158 0x60, 0x00,
159
160
161
162 0x67, 0x00,
163 0x68, 0x00,
164 0x69, 0x00,
165 0x6a, 0x00,
166
167 0x6b, 0x91,
168 0x6c, 0x20,
169
170 0x6d, 0x00,
171
172 0x6e, 0x0e,
173
174 0x6f, 0x00,
175 0x70, 0x20,
176
177
178
179 0x71, 0x15,
180 0x72, 0x90,
181 0x73, 0x61,
182 0x74, 0x00,
183 0x75, 0x00,
184 0x76, 0x00,
185 0x77, 0x15,
186 0x78, 0x90,
187 0x79, 0x61,
188
189
190
191 0x7a, 0x70,
192
193
194
195 0x7b, 0x16,
196 0x7c, 0x35,
197 0x7d, 0x20,
198};
199
200static const unsigned char init_pal[] = {
201 0x61, 0x1e,
202
203 0x62, 0xc8,
204 0x63, 0xcb,
205 0x64, 0x8a,
206 0x65, 0x09,
207 0x66, 0x2a,
208};
209
210static const unsigned char init_ntsc[] = {
211 0x61, 0x1d,
212
213 0x62, 0xe6,
214 0x63, 0x1f,
215 0x64, 0x7c,
216 0x65, 0xf0,
217 0x66, 0x21,
218};
219
220
221static int saa7185_init(struct v4l2_subdev *sd, u32 val)
222{
223 struct saa7185 *encoder = to_saa7185(sd);
224
225 saa7185_write_block(sd, init_common, sizeof(init_common));
226 if (encoder->norm & V4L2_STD_NTSC)
227 saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
228 else
229 saa7185_write_block(sd, init_pal, sizeof(init_pal));
230 return 0;
231}
232
233static int saa7185_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
234{
235 struct saa7185 *encoder = to_saa7185(sd);
236
237 if (std & V4L2_STD_NTSC)
238 saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
239 else if (std & V4L2_STD_PAL)
240 saa7185_write_block(sd, init_pal, sizeof(init_pal));
241 else
242 return -EINVAL;
243 encoder->norm = std;
244 return 0;
245}
246
247static int saa7185_s_routing(struct v4l2_subdev *sd,
248 u32 input, u32 output, u32 config)
249{
250 struct saa7185 *encoder = to_saa7185(sd);
251
252
253
254
255 switch (input) {
256 case 0:
257
258 saa7185_write(sd, 0x3a, 0x0f);
259
260 saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
261 saa7185_write(sd, 0x6e, 0x01);
262 break;
263
264 case 1:
265
266 saa7185_write(sd, 0x3a, 0x0f);
267
268 saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x00);
269
270 saa7185_write(sd, 0x6e, 0x00);
271 break;
272
273 case 2:
274
275 saa7185_write(sd, 0x3a, 0x8f);
276
277 saa7185_write(sd, 0x61, (encoder->reg[0x61] & 0xf7) | 0x08);
278
279 saa7185_write(sd, 0x6e, 0x01);
280 break;
281
282 default:
283 return -EINVAL;
284 }
285 return 0;
286}
287
288static int saa7185_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
289{
290 struct i2c_client *client = v4l2_get_subdevdata(sd);
291
292 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA7185, 0);
293}
294
295
296
297static const struct v4l2_subdev_core_ops saa7185_core_ops = {
298 .g_chip_ident = saa7185_g_chip_ident,
299 .init = saa7185_init,
300};
301
302static const struct v4l2_subdev_video_ops saa7185_video_ops = {
303 .s_std_output = saa7185_s_std_output,
304 .s_routing = saa7185_s_routing,
305};
306
307static const struct v4l2_subdev_ops saa7185_ops = {
308 .core = &saa7185_core_ops,
309 .video = &saa7185_video_ops,
310};
311
312
313
314
315static int saa7185_probe(struct i2c_client *client,
316 const struct i2c_device_id *id)
317{
318 int i;
319 struct saa7185 *encoder;
320 struct v4l2_subdev *sd;
321
322
323 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
324 return -ENODEV;
325
326 v4l_info(client, "chip found @ 0x%x (%s)\n",
327 client->addr << 1, client->adapter->name);
328
329 encoder = kzalloc(sizeof(struct saa7185), GFP_KERNEL);
330 if (encoder == NULL)
331 return -ENOMEM;
332 encoder->norm = V4L2_STD_NTSC;
333 sd = &encoder->sd;
334 v4l2_i2c_subdev_init(sd, client, &saa7185_ops);
335
336 i = saa7185_write_block(sd, init_common, sizeof(init_common));
337 if (i >= 0)
338 i = saa7185_write_block(sd, init_ntsc, sizeof(init_ntsc));
339 if (i < 0)
340 v4l2_dbg(1, debug, sd, "init error %d\n", i);
341 else
342 v4l2_dbg(1, debug, sd, "revision 0x%x\n",
343 saa7185_read(sd) >> 5);
344 return 0;
345}
346
347static int saa7185_remove(struct i2c_client *client)
348{
349 struct v4l2_subdev *sd = i2c_get_clientdata(client);
350 struct saa7185 *encoder = to_saa7185(sd);
351
352 v4l2_device_unregister_subdev(sd);
353
354 saa7185_write(sd, 0x61, (encoder->reg[0x61]) | 0x40);
355 kfree(encoder);
356 return 0;
357}
358
359
360
361static const struct i2c_device_id saa7185_id[] = {
362 { "saa7185", 0 },
363 { }
364};
365MODULE_DEVICE_TABLE(i2c, saa7185_id);
366
367static struct i2c_driver saa7185_driver = {
368 .driver = {
369 .owner = THIS_MODULE,
370 .name = "saa7185",
371 },
372 .probe = saa7185_probe,
373 .remove = saa7185_remove,
374 .id_table = saa7185_id,
375};
376
377static __init int init_saa7185(void)
378{
379 return i2c_add_driver(&saa7185_driver);
380}
381
382static __exit void exit_saa7185(void)
383{
384 i2c_del_driver(&saa7185_driver);
385}
386
387module_init(init_saa7185);
388module_exit(exit_saa7185);
389