1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * cxd2099.c: Driver for the Sony CXD2099AR Common Interface Controller |
4 | * |
5 | * Copyright (C) 2010-2013 Digital Devices GmbH |
6 | */ |
7 | |
8 | #include <linux/slab.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/module.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/regmap.h> |
13 | #include <linux/wait.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/mutex.h> |
16 | #include <linux/io.h> |
17 | |
18 | #include "cxd2099.h" |
19 | |
20 | static int buffermode; |
21 | module_param(buffermode, int, 0444); |
22 | MODULE_PARM_DESC(buffermode, "Enable CXD2099AR buffer mode (default: disabled)" ); |
23 | |
24 | static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount); |
25 | |
26 | struct cxd { |
27 | struct dvb_ca_en50221 en; |
28 | |
29 | struct cxd2099_cfg cfg; |
30 | struct i2c_client *client; |
31 | struct regmap *regmap; |
32 | |
33 | u8 regs[0x23]; |
34 | u8 lastaddress; |
35 | u8 clk_reg_f; |
36 | u8 clk_reg_b; |
37 | int mode; |
38 | int ready; |
39 | int dr; |
40 | int write_busy; |
41 | int slot_stat; |
42 | |
43 | u8 amem[1024]; |
44 | int amem_read; |
45 | |
46 | int cammode; |
47 | struct mutex lock; /* device access lock */ |
48 | |
49 | u8 rbuf[1028]; |
50 | u8 wbuf[1028]; |
51 | }; |
52 | |
53 | static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n) |
54 | { |
55 | int status = 0; |
56 | |
57 | if (ci->lastaddress != adr) |
58 | status = regmap_write(map: ci->regmap, reg: 0, val: adr); |
59 | if (!status) { |
60 | ci->lastaddress = adr; |
61 | |
62 | while (n) { |
63 | int len = n; |
64 | |
65 | if (ci->cfg.max_i2c && len > ci->cfg.max_i2c) |
66 | len = ci->cfg.max_i2c; |
67 | status = regmap_raw_read(map: ci->regmap, reg: 1, val: data, val_len: len); |
68 | if (status) |
69 | return status; |
70 | data += len; |
71 | n -= len; |
72 | } |
73 | } |
74 | return status; |
75 | } |
76 | |
77 | static int read_reg(struct cxd *ci, u8 reg, u8 *val) |
78 | { |
79 | return read_block(ci, adr: reg, data: val, n: 1); |
80 | } |
81 | |
82 | static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) |
83 | { |
84 | int status; |
85 | u8 addr[2] = {address & 0xff, address >> 8}; |
86 | |
87 | status = regmap_raw_write(map: ci->regmap, reg: 2, val: addr, val_len: 2); |
88 | if (!status) |
89 | status = regmap_raw_read(map: ci->regmap, reg: 3, val: data, val_len: n); |
90 | return status; |
91 | } |
92 | |
93 | static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) |
94 | { |
95 | int status; |
96 | u8 addr[2] = {address & 0xff, address >> 8}; |
97 | |
98 | status = regmap_raw_write(map: ci->regmap, reg: 2, val: addr, val_len: 2); |
99 | if (!status) { |
100 | u8 buf[256]; |
101 | |
102 | memcpy(buf, data, n); |
103 | status = regmap_raw_write(map: ci->regmap, reg: 3, val: buf, val_len: n); |
104 | } |
105 | return status; |
106 | } |
107 | |
108 | static int read_io(struct cxd *ci, u16 address, unsigned int *val) |
109 | { |
110 | int status; |
111 | u8 addr[2] = {address & 0xff, address >> 8}; |
112 | |
113 | status = regmap_raw_write(map: ci->regmap, reg: 2, val: addr, val_len: 2); |
114 | if (!status) |
115 | status = regmap_read(map: ci->regmap, reg: 3, val); |
116 | return status; |
117 | } |
118 | |
119 | static int write_io(struct cxd *ci, u16 address, u8 val) |
120 | { |
121 | int status; |
122 | u8 addr[2] = {address & 0xff, address >> 8}; |
123 | |
124 | status = regmap_raw_write(map: ci->regmap, reg: 2, val: addr, val_len: 2); |
125 | if (!status) |
126 | status = regmap_write(map: ci->regmap, reg: 3, val); |
127 | return status; |
128 | } |
129 | |
130 | static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask) |
131 | { |
132 | int status = 0; |
133 | unsigned int regval; |
134 | |
135 | if (ci->lastaddress != reg) |
136 | status = regmap_write(map: ci->regmap, reg: 0, val: reg); |
137 | if (!status && reg >= 6 && reg <= 8 && mask != 0xff) { |
138 | status = regmap_read(map: ci->regmap, reg: 1, val: ®val); |
139 | ci->regs[reg] = regval; |
140 | } |
141 | ci->lastaddress = reg; |
142 | ci->regs[reg] = (ci->regs[reg] & (~mask)) | val; |
143 | if (!status) |
144 | status = regmap_write(map: ci->regmap, reg: 1, val: ci->regs[reg]); |
145 | if (reg == 0x20) |
146 | ci->regs[reg] &= 0x7f; |
147 | return status; |
148 | } |
149 | |
150 | static int write_reg(struct cxd *ci, u8 reg, u8 val) |
151 | { |
152 | return write_regm(ci, reg, val, mask: 0xff); |
153 | } |
154 | |
155 | static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n) |
156 | { |
157 | int status = 0; |
158 | u8 *buf = ci->wbuf; |
159 | |
160 | if (ci->lastaddress != adr) |
161 | status = regmap_write(map: ci->regmap, reg: 0, val: adr); |
162 | if (status) |
163 | return status; |
164 | |
165 | ci->lastaddress = adr; |
166 | while (n) { |
167 | int len = n; |
168 | |
169 | if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c)) |
170 | len = ci->cfg.max_i2c - 1; |
171 | memcpy(buf, data, len); |
172 | status = regmap_raw_write(map: ci->regmap, reg: 1, val: buf, val_len: len); |
173 | if (status) |
174 | return status; |
175 | n -= len; |
176 | data += len; |
177 | } |
178 | return status; |
179 | } |
180 | |
181 | static void set_mode(struct cxd *ci, int mode) |
182 | { |
183 | if (mode == ci->mode) |
184 | return; |
185 | |
186 | switch (mode) { |
187 | case 0x00: /* IO mem */ |
188 | write_regm(ci, reg: 0x06, val: 0x00, mask: 0x07); |
189 | break; |
190 | case 0x01: /* ATT mem */ |
191 | write_regm(ci, reg: 0x06, val: 0x02, mask: 0x07); |
192 | break; |
193 | default: |
194 | break; |
195 | } |
196 | ci->mode = mode; |
197 | } |
198 | |
199 | static void cam_mode(struct cxd *ci, int mode) |
200 | { |
201 | u8 dummy; |
202 | |
203 | if (mode == ci->cammode) |
204 | return; |
205 | |
206 | switch (mode) { |
207 | case 0x00: |
208 | write_regm(ci, reg: 0x20, val: 0x80, mask: 0x80); |
209 | break; |
210 | case 0x01: |
211 | if (!ci->en.read_data) |
212 | return; |
213 | ci->write_busy = 0; |
214 | dev_info(&ci->client->dev, "enable cam buffer mode\n" ); |
215 | write_reg(ci, reg: 0x0d, val: 0x00); |
216 | write_reg(ci, reg: 0x0e, val: 0x01); |
217 | write_regm(ci, reg: 0x08, val: 0x40, mask: 0x40); |
218 | read_reg(ci, reg: 0x12, val: &dummy); |
219 | write_regm(ci, reg: 0x08, val: 0x80, mask: 0x80); |
220 | break; |
221 | default: |
222 | break; |
223 | } |
224 | ci->cammode = mode; |
225 | } |
226 | |
227 | static int init(struct cxd *ci) |
228 | { |
229 | int status; |
230 | |
231 | mutex_lock(&ci->lock); |
232 | ci->mode = -1; |
233 | do { |
234 | status = write_reg(ci, reg: 0x00, val: 0x00); |
235 | if (status < 0) |
236 | break; |
237 | status = write_reg(ci, reg: 0x01, val: 0x00); |
238 | if (status < 0) |
239 | break; |
240 | status = write_reg(ci, reg: 0x02, val: 0x10); |
241 | if (status < 0) |
242 | break; |
243 | status = write_reg(ci, reg: 0x03, val: 0x00); |
244 | if (status < 0) |
245 | break; |
246 | status = write_reg(ci, reg: 0x05, val: 0xFF); |
247 | if (status < 0) |
248 | break; |
249 | status = write_reg(ci, reg: 0x06, val: 0x1F); |
250 | if (status < 0) |
251 | break; |
252 | status = write_reg(ci, reg: 0x07, val: 0x1F); |
253 | if (status < 0) |
254 | break; |
255 | status = write_reg(ci, reg: 0x08, val: 0x28); |
256 | if (status < 0) |
257 | break; |
258 | status = write_reg(ci, reg: 0x14, val: 0x20); |
259 | if (status < 0) |
260 | break; |
261 | |
262 | /* TOSTRT = 8, Mode B (gated clock), falling Edge, |
263 | * Serial, POL=HIGH, MSB |
264 | */ |
265 | status = write_reg(ci, reg: 0x0A, val: 0xA7); |
266 | if (status < 0) |
267 | break; |
268 | |
269 | status = write_reg(ci, reg: 0x0B, val: 0x33); |
270 | if (status < 0) |
271 | break; |
272 | status = write_reg(ci, reg: 0x0C, val: 0x33); |
273 | if (status < 0) |
274 | break; |
275 | |
276 | status = write_regm(ci, reg: 0x14, val: 0x00, mask: 0x0F); |
277 | if (status < 0) |
278 | break; |
279 | status = write_reg(ci, reg: 0x15, val: ci->clk_reg_b); |
280 | if (status < 0) |
281 | break; |
282 | status = write_regm(ci, reg: 0x16, val: 0x00, mask: 0x0F); |
283 | if (status < 0) |
284 | break; |
285 | status = write_reg(ci, reg: 0x17, val: ci->clk_reg_f); |
286 | if (status < 0) |
287 | break; |
288 | |
289 | if (ci->cfg.clock_mode == 2) { |
290 | /* bitrate*2^13/ 72000 */ |
291 | u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000; |
292 | |
293 | if (ci->cfg.polarity) { |
294 | status = write_reg(ci, reg: 0x09, val: 0x6f); |
295 | if (status < 0) |
296 | break; |
297 | } else { |
298 | status = write_reg(ci, reg: 0x09, val: 0x6d); |
299 | if (status < 0) |
300 | break; |
301 | } |
302 | status = write_reg(ci, reg: 0x20, val: 0x08); |
303 | if (status < 0) |
304 | break; |
305 | status = write_reg(ci, reg: 0x21, val: (reg >> 8) & 0xff); |
306 | if (status < 0) |
307 | break; |
308 | status = write_reg(ci, reg: 0x22, val: reg & 0xff); |
309 | if (status < 0) |
310 | break; |
311 | } else if (ci->cfg.clock_mode == 1) { |
312 | if (ci->cfg.polarity) { |
313 | status = write_reg(ci, reg: 0x09, val: 0x6f); /* D */ |
314 | if (status < 0) |
315 | break; |
316 | } else { |
317 | status = write_reg(ci, reg: 0x09, val: 0x6d); |
318 | if (status < 0) |
319 | break; |
320 | } |
321 | status = write_reg(ci, reg: 0x20, val: 0x68); |
322 | if (status < 0) |
323 | break; |
324 | status = write_reg(ci, reg: 0x21, val: 0x00); |
325 | if (status < 0) |
326 | break; |
327 | status = write_reg(ci, reg: 0x22, val: 0x02); |
328 | if (status < 0) |
329 | break; |
330 | } else { |
331 | if (ci->cfg.polarity) { |
332 | status = write_reg(ci, reg: 0x09, val: 0x4f); /* C */ |
333 | if (status < 0) |
334 | break; |
335 | } else { |
336 | status = write_reg(ci, reg: 0x09, val: 0x4d); |
337 | if (status < 0) |
338 | break; |
339 | } |
340 | status = write_reg(ci, reg: 0x20, val: 0x28); |
341 | if (status < 0) |
342 | break; |
343 | status = write_reg(ci, reg: 0x21, val: 0x00); |
344 | if (status < 0) |
345 | break; |
346 | status = write_reg(ci, reg: 0x22, val: 0x07); |
347 | if (status < 0) |
348 | break; |
349 | } |
350 | |
351 | status = write_regm(ci, reg: 0x20, val: 0x80, mask: 0x80); |
352 | if (status < 0) |
353 | break; |
354 | status = write_regm(ci, reg: 0x03, val: 0x02, mask: 0x02); |
355 | if (status < 0) |
356 | break; |
357 | status = write_reg(ci, reg: 0x01, val: 0x04); |
358 | if (status < 0) |
359 | break; |
360 | status = write_reg(ci, reg: 0x00, val: 0x31); |
361 | if (status < 0) |
362 | break; |
363 | |
364 | /* Put TS in bypass */ |
365 | status = write_regm(ci, reg: 0x09, val: 0x08, mask: 0x08); |
366 | if (status < 0) |
367 | break; |
368 | ci->cammode = -1; |
369 | cam_mode(ci, mode: 0); |
370 | } while (0); |
371 | mutex_unlock(lock: &ci->lock); |
372 | |
373 | return 0; |
374 | } |
375 | |
376 | static int read_attribute_mem(struct dvb_ca_en50221 *ca, |
377 | int slot, int address) |
378 | { |
379 | struct cxd *ci = ca->data; |
380 | u8 val; |
381 | |
382 | mutex_lock(&ci->lock); |
383 | set_mode(ci, mode: 1); |
384 | read_pccard(ci, address, data: &val, n: 1); |
385 | mutex_unlock(lock: &ci->lock); |
386 | return val; |
387 | } |
388 | |
389 | static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, |
390 | int address, u8 value) |
391 | { |
392 | struct cxd *ci = ca->data; |
393 | |
394 | mutex_lock(&ci->lock); |
395 | set_mode(ci, mode: 1); |
396 | write_pccard(ci, address, data: &value, n: 1); |
397 | mutex_unlock(lock: &ci->lock); |
398 | return 0; |
399 | } |
400 | |
401 | static int read_cam_control(struct dvb_ca_en50221 *ca, |
402 | int slot, u8 address) |
403 | { |
404 | struct cxd *ci = ca->data; |
405 | unsigned int val; |
406 | |
407 | mutex_lock(&ci->lock); |
408 | set_mode(ci, mode: 0); |
409 | read_io(ci, address, val: &val); |
410 | mutex_unlock(lock: &ci->lock); |
411 | return val; |
412 | } |
413 | |
414 | static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, |
415 | u8 address, u8 value) |
416 | { |
417 | struct cxd *ci = ca->data; |
418 | |
419 | mutex_lock(&ci->lock); |
420 | set_mode(ci, mode: 0); |
421 | write_io(ci, address, val: value); |
422 | mutex_unlock(lock: &ci->lock); |
423 | return 0; |
424 | } |
425 | |
426 | static int slot_reset(struct dvb_ca_en50221 *ca, int slot) |
427 | { |
428 | struct cxd *ci = ca->data; |
429 | |
430 | if (ci->cammode) |
431 | read_data(ca, slot, ebuf: ci->rbuf, ecount: 0); |
432 | |
433 | mutex_lock(&ci->lock); |
434 | cam_mode(ci, mode: 0); |
435 | write_reg(ci, reg: 0x00, val: 0x21); |
436 | write_reg(ci, reg: 0x06, val: 0x1F); |
437 | write_reg(ci, reg: 0x00, val: 0x31); |
438 | write_regm(ci, reg: 0x20, val: 0x80, mask: 0x80); |
439 | write_reg(ci, reg: 0x03, val: 0x02); |
440 | ci->ready = 0; |
441 | ci->mode = -1; |
442 | { |
443 | int i; |
444 | |
445 | for (i = 0; i < 100; i++) { |
446 | usleep_range(min: 10000, max: 11000); |
447 | if (ci->ready) |
448 | break; |
449 | } |
450 | } |
451 | mutex_unlock(lock: &ci->lock); |
452 | return 0; |
453 | } |
454 | |
455 | static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) |
456 | { |
457 | struct cxd *ci = ca->data; |
458 | |
459 | dev_dbg(&ci->client->dev, "%s\n" , __func__); |
460 | if (ci->cammode) |
461 | read_data(ca, slot, ebuf: ci->rbuf, ecount: 0); |
462 | mutex_lock(&ci->lock); |
463 | write_reg(ci, reg: 0x00, val: 0x21); |
464 | write_reg(ci, reg: 0x06, val: 0x1F); |
465 | msleep(msecs: 300); |
466 | |
467 | write_regm(ci, reg: 0x09, val: 0x08, mask: 0x08); |
468 | write_regm(ci, reg: 0x20, val: 0x80, mask: 0x80); /* Reset CAM Mode */ |
469 | write_regm(ci, reg: 0x06, val: 0x07, mask: 0x07); /* Clear IO Mode */ |
470 | |
471 | ci->mode = -1; |
472 | ci->write_busy = 0; |
473 | mutex_unlock(lock: &ci->lock); |
474 | return 0; |
475 | } |
476 | |
477 | static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) |
478 | { |
479 | struct cxd *ci = ca->data; |
480 | |
481 | mutex_lock(&ci->lock); |
482 | write_regm(ci, reg: 0x09, val: 0x00, mask: 0x08); |
483 | set_mode(ci, mode: 0); |
484 | cam_mode(ci, mode: 1); |
485 | mutex_unlock(lock: &ci->lock); |
486 | return 0; |
487 | } |
488 | |
489 | static int campoll(struct cxd *ci) |
490 | { |
491 | u8 istat; |
492 | |
493 | read_reg(ci, reg: 0x04, val: &istat); |
494 | if (!istat) |
495 | return 0; |
496 | write_reg(ci, reg: 0x05, val: istat); |
497 | |
498 | if (istat & 0x40) |
499 | ci->dr = 1; |
500 | if (istat & 0x20) |
501 | ci->write_busy = 0; |
502 | |
503 | if (istat & 2) { |
504 | u8 slotstat; |
505 | |
506 | read_reg(ci, reg: 0x01, val: &slotstat); |
507 | if (!(2 & slotstat)) { |
508 | if (!ci->slot_stat) { |
509 | ci->slot_stat |= |
510 | DVB_CA_EN50221_POLL_CAM_PRESENT; |
511 | write_regm(ci, reg: 0x03, val: 0x08, mask: 0x08); |
512 | } |
513 | |
514 | } else { |
515 | if (ci->slot_stat) { |
516 | ci->slot_stat = 0; |
517 | write_regm(ci, reg: 0x03, val: 0x00, mask: 0x08); |
518 | dev_info(&ci->client->dev, "NO CAM\n" ); |
519 | ci->ready = 0; |
520 | } |
521 | } |
522 | if ((istat & 8) && |
523 | ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) { |
524 | ci->ready = 1; |
525 | ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY; |
526 | } |
527 | } |
528 | return 0; |
529 | } |
530 | |
531 | static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) |
532 | { |
533 | struct cxd *ci = ca->data; |
534 | u8 slotstat; |
535 | |
536 | mutex_lock(&ci->lock); |
537 | campoll(ci); |
538 | read_reg(ci, reg: 0x01, val: &slotstat); |
539 | mutex_unlock(lock: &ci->lock); |
540 | |
541 | return ci->slot_stat; |
542 | } |
543 | |
544 | static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) |
545 | { |
546 | struct cxd *ci = ca->data; |
547 | u8 msb, lsb; |
548 | u16 len; |
549 | |
550 | mutex_lock(&ci->lock); |
551 | campoll(ci); |
552 | mutex_unlock(lock: &ci->lock); |
553 | |
554 | if (!ci->dr) |
555 | return 0; |
556 | |
557 | mutex_lock(&ci->lock); |
558 | read_reg(ci, reg: 0x0f, val: &msb); |
559 | read_reg(ci, reg: 0x10, val: &lsb); |
560 | len = ((u16)msb << 8) | lsb; |
561 | if (len > ecount || len < 2) { |
562 | /* read it anyway or cxd may hang */ |
563 | read_block(ci, adr: 0x12, data: ci->rbuf, n: len); |
564 | mutex_unlock(lock: &ci->lock); |
565 | return -EIO; |
566 | } |
567 | read_block(ci, adr: 0x12, data: ebuf, n: len); |
568 | ci->dr = 0; |
569 | mutex_unlock(lock: &ci->lock); |
570 | return len; |
571 | } |
572 | |
573 | static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) |
574 | { |
575 | struct cxd *ci = ca->data; |
576 | |
577 | if (ci->write_busy) |
578 | return -EAGAIN; |
579 | mutex_lock(&ci->lock); |
580 | write_reg(ci, reg: 0x0d, val: ecount >> 8); |
581 | write_reg(ci, reg: 0x0e, val: ecount & 0xff); |
582 | write_block(ci, adr: 0x11, data: ebuf, n: ecount); |
583 | ci->write_busy = 1; |
584 | mutex_unlock(lock: &ci->lock); |
585 | return ecount; |
586 | } |
587 | |
588 | static const struct dvb_ca_en50221 en_templ = { |
589 | .read_attribute_mem = read_attribute_mem, |
590 | .write_attribute_mem = write_attribute_mem, |
591 | .read_cam_control = read_cam_control, |
592 | .write_cam_control = write_cam_control, |
593 | .slot_reset = slot_reset, |
594 | .slot_shutdown = slot_shutdown, |
595 | .slot_ts_enable = slot_ts_enable, |
596 | .poll_slot_status = poll_slot_status, |
597 | .read_data = read_data, |
598 | .write_data = write_data, |
599 | }; |
600 | |
601 | static int cxd2099_probe(struct i2c_client *client) |
602 | { |
603 | struct cxd *ci; |
604 | struct cxd2099_cfg *cfg = client->dev.platform_data; |
605 | static const struct regmap_config rm_cfg = { |
606 | .reg_bits = 8, |
607 | .val_bits = 8, |
608 | }; |
609 | unsigned int val; |
610 | int ret; |
611 | |
612 | ci = kzalloc(size: sizeof(*ci), GFP_KERNEL); |
613 | if (!ci) { |
614 | ret = -ENOMEM; |
615 | goto err; |
616 | } |
617 | |
618 | ci->client = client; |
619 | memcpy(&ci->cfg, cfg, sizeof(ci->cfg)); |
620 | |
621 | ci->regmap = regmap_init_i2c(client, &rm_cfg); |
622 | if (IS_ERR(ptr: ci->regmap)) { |
623 | ret = PTR_ERR(ptr: ci->regmap); |
624 | goto err_kfree; |
625 | } |
626 | |
627 | ret = regmap_read(map: ci->regmap, reg: 0x00, val: &val); |
628 | if (ret < 0) { |
629 | dev_info(&client->dev, "No CXD2099AR detected at 0x%02x\n" , |
630 | client->addr); |
631 | goto err_rmexit; |
632 | } |
633 | |
634 | mutex_init(&ci->lock); |
635 | ci->lastaddress = 0xff; |
636 | ci->clk_reg_b = 0x4a; |
637 | ci->clk_reg_f = 0x1b; |
638 | |
639 | ci->en = en_templ; |
640 | ci->en.data = ci; |
641 | init(ci); |
642 | dev_info(&client->dev, "Attached CXD2099AR at 0x%02x\n" , client->addr); |
643 | |
644 | *cfg->en = &ci->en; |
645 | |
646 | if (!buffermode) { |
647 | ci->en.read_data = NULL; |
648 | ci->en.write_data = NULL; |
649 | } else { |
650 | dev_info(&client->dev, "Using CXD2099AR buffer mode" ); |
651 | } |
652 | |
653 | i2c_set_clientdata(client, data: ci); |
654 | |
655 | return 0; |
656 | |
657 | err_rmexit: |
658 | regmap_exit(map: ci->regmap); |
659 | err_kfree: |
660 | kfree(objp: ci); |
661 | err: |
662 | |
663 | return ret; |
664 | } |
665 | |
666 | static void cxd2099_remove(struct i2c_client *client) |
667 | { |
668 | struct cxd *ci = i2c_get_clientdata(client); |
669 | |
670 | regmap_exit(map: ci->regmap); |
671 | kfree(objp: ci); |
672 | } |
673 | |
674 | static const struct i2c_device_id cxd2099_id[] = { |
675 | {"cxd2099" , 0}, |
676 | {} |
677 | }; |
678 | MODULE_DEVICE_TABLE(i2c, cxd2099_id); |
679 | |
680 | static struct i2c_driver cxd2099_driver = { |
681 | .driver = { |
682 | .name = "cxd2099" , |
683 | }, |
684 | .probe = cxd2099_probe, |
685 | .remove = cxd2099_remove, |
686 | .id_table = cxd2099_id, |
687 | }; |
688 | |
689 | module_i2c_driver(cxd2099_driver); |
690 | |
691 | MODULE_DESCRIPTION("Sony CXD2099AR Common Interface controller driver" ); |
692 | MODULE_AUTHOR("Ralph Metzler" ); |
693 | MODULE_LICENSE("GPL v2" ); |
694 | |