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