i2s: add support samplerate up to 192K and support S32_LE
[firefly-linux-kernel-4.4.55.git] / drivers / video / display / transmitter / tc358768.c
1 /*
2  * Copyright (C) 2012 ROCKCHIP, Inc.
3  * drivers/video/display/transmitter/tc358768.c
4  * author: hhb@rock-chips.com
5  * create date: 2012-10-26
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15 #include <linux/fb.h>
16 #include <linux/delay.h>
17 #include <linux/rk_fb.h>
18 #include <mach/gpio.h>
19 #include <mach/iomux.h>
20 #include <mach/board.h>
21 #include <linux/rk_screen.h>
22 #include <linux/ktime.h>
23 #include "mipi_dsi.h"
24
25 #define CONFIG_TC358768_I2C     1
26 #define CONFIG_TC358768_I2C_CLK     400*1000
27
28
29 #if 0
30 #define dsi_debug   printk
31 #else
32 #define dsi_debug(fmt...)   do { } while (0)
33 #endif
34
35 #ifdef CONFIG_TC358768_I2C
36 static struct tc358768_t *tc358768 = NULL;
37 static struct i2c_client *tc358768_client = NULL;
38 static struct mipi_dsi_ops tc358768_ops;
39
40
41 u32 i2c_write_32bits(u32 value) 
42 {
43         struct i2c_msg msgs;
44         int ret = -1;
45         char buf[4];
46         buf[0] = value>>24;
47         buf[1] = value>>16;
48         buf[2] = value>>8;
49         buf[3] = value;
50         
51         msgs.addr = tc358768_client->addr;
52         msgs.flags = tc358768_client->flags;
53         msgs.len = 4;
54         msgs.buf = buf;
55         msgs.scl_rate = CONFIG_TC358768_I2C_CLK;
56         msgs.udelay = tc358768_client->udelay;
57
58         ret = i2c_transfer(tc358768_client->adapter, &msgs, 1);
59         if(ret < 0)
60                 printk("%s:i2c_transfer fail =%d\n",__func__, ret);
61         return ret;
62 }
63
64 u32 i2c_read_32bits(u32 value) 
65 {
66         struct i2c_msg msgs[2];
67         int ret = -1;
68         char buf[4];
69         buf[0] = value>>8;
70         buf[1] = value;
71         
72         msgs[0].addr = tc358768_client->addr;
73         msgs[0].flags = tc358768_client->flags;
74         msgs[0].len = 2;
75         msgs[0].buf = buf;
76         msgs[0].scl_rate = CONFIG_TC358768_I2C_CLK;
77         msgs[0].udelay = tc358768_client->udelay;
78
79         msgs[1].addr = tc358768_client->addr;
80         msgs[1].flags = tc358768_client->flags | I2C_M_RD;
81         msgs[1].len = 2;
82         msgs[1].buf = buf;
83         msgs[1].scl_rate = CONFIG_TC358768_I2C_CLK;
84         msgs[1].udelay = tc358768_client->udelay;
85
86         ret = i2c_transfer(tc358768_client->adapter, msgs, 2);
87         if(ret < 0)
88                 printk("%s:i2c_transfer fail =%d\n",__func__, ret);
89         else
90                 ret = (buf[0]<<8) | buf[1];     
91         
92         return ret;
93 }
94
95
96 int tc358768_gpio_init(void *data) {
97         int ret = 0;
98         struct reset_t *reset = &tc358768->reset;
99         struct power_t *vdd = &tc358768->vddc;
100         if(reset->reset_pin > INVALID_GPIO) {
101                 ret = gpio_request(reset->reset_pin, "tc358768_reset");
102                 if (ret != 0) {
103                         //gpio_free(reset->reset_pin);
104                         printk("%s: request TC358768_RST_PIN error\n", __func__);
105                 } else {
106 #if OLD_RK_IOMUX                
107                         if(reset->mux_name)
108                                 rk30_mux_api_set(reset->mux_name, reset->mux_mode);
109 #endif
110                         gpio_direction_output(reset->reset_pin, !reset->effect_value);
111                 }
112         }
113         
114         if(vdd->enable_pin > INVALID_GPIO) {
115                 ret = gpio_request(vdd->enable_pin, "tc358768_vddc");
116                 if (ret != 0) {
117                         //gpio_free(vdd->enable_pin);
118                         printk("%s: request TC358768_vddc_PIN error\n", __func__);
119                 } else {
120 #if OLD_RK_IOMUX                
121                         if(vdd->mux_name)
122                                 rk30_mux_api_set(vdd->mux_name, vdd->mux_mode); 
123 #endif
124                         gpio_direction_output(vdd->enable_pin, !vdd->effect_value);
125                 }
126         }
127         
128         vdd = &tc358768->vddio;
129         if(vdd->enable_pin > INVALID_GPIO) {
130                 ret = gpio_request(vdd->enable_pin, "tc358768_vddio");
131                 if (ret != 0) {
132                         //gpio_free(vdd->enable_pin);
133                         printk("%s: request TC358768_vddio_PIN error\n", __func__);
134                 } else {
135 #if OLD_RK_IOMUX                
136                         if(vdd->mux_name)
137                                 rk30_mux_api_set(vdd->mux_name, vdd->mux_mode); 
138 #endif
139                         gpio_direction_output(vdd->enable_pin, !vdd->effect_value);     
140                 }
141         }
142         
143         vdd = &tc358768->vdd_mipi;
144         if(vdd->enable_pin > INVALID_GPIO) {
145                 ret = gpio_request(vdd->enable_pin, "tc358768_vdd_mipi");
146                 if (ret != 0) {
147                         //gpio_free(vdd->enable_pin);
148                         printk("%s: request TC358768_vdd_mipi_PIN error\n", __func__);
149                 } else {
150 #if OLD_RK_IOMUX                
151                         if(vdd->mux_name)
152                                 rk30_mux_api_set(vdd->mux_name, vdd->mux_mode); 
153 #endif
154                         gpio_direction_output(vdd->enable_pin, !vdd->effect_value);     
155                 }
156         }
157         return 0;
158
159 }
160
161 int tc358768_gpio_deinit(void *data) {
162         struct reset_t *reset = &tc358768->reset;
163         struct power_t *vdd = &tc358768->vddc;
164         gpio_direction_input(reset->reset_pin);
165         gpio_free(reset->reset_pin);
166         
167         gpio_direction_input(vdd->enable_pin);
168         gpio_free(vdd->enable_pin);
169         
170         vdd = &tc358768->vddio;
171         gpio_direction_input(vdd->enable_pin);
172         gpio_free(vdd->enable_pin);
173         
174         vdd = &tc358768->vdd_mipi;
175         gpio_direction_input(vdd->enable_pin);
176         gpio_free(vdd->enable_pin);
177         return 0;
178 }
179
180 int tc358768_reset(void *data) {
181         int ret = 0;
182         struct reset_t *reset = &tc358768->reset;
183         if(reset->reset_pin <= INVALID_GPIO)
184                 return -1;
185         gpio_set_value(reset->reset_pin, reset->effect_value);
186         if(reset->time_before_reset <= 0)
187                 msleep(1);
188         else
189                 msleep(reset->time_before_reset);
190         
191         gpio_set_value(reset->reset_pin, !reset->effect_value);
192         if(reset->time_after_reset <= 0)
193                 msleep(5);
194         else
195                 msleep(reset->time_after_reset);
196         return ret;     
197 }
198
199 int tc358768_vdd_enable(void *data) {
200         int ret = 0;
201         struct power_t *vdd = (struct power_t *)data;
202         if(vdd->enable_pin > INVALID_GPIO) {
203                 gpio_set_value(vdd->enable_pin, vdd->effect_value);
204         } else {
205                 //for other control
206         }
207         return ret;
208 }
209
210 int tc358768_vdd_disable(void *data) {
211         int ret = 0;
212         struct power_t *vdd = (struct power_t *)data;
213         
214         if(vdd->enable_pin > INVALID_GPIO) {
215                 gpio_set_value(vdd->enable_pin, !vdd->effect_value);
216         } else {
217                 //for other control
218         }
219         return ret;
220 }
221
222
223 int tc358768_power_up(void) {
224
225         int ret = 0;
226         struct tc358768_t *tc = (struct tc358768_t *)tc358768;
227         
228         tc->vddc.enable(&tc->vddc);
229         tc->vdd_mipi.enable(&tc->vdd_mipi);
230         tc->vddio.enable(&tc->vddio);
231         tc->reset.do_reset(&tc->reset);
232         
233         return ret;
234 }
235
236 int tc358768_power_down(void) {
237
238         int ret = 0;
239         struct tc358768_t *tc = (struct tc358768_t *)tc358768;
240         
241         tc->vddio.disable(&tc->vddio);
242         tc->vdd_mipi.disable(&tc->vdd_mipi);
243         tc->vddc.disable(&tc->vddc);
244         
245         return ret;
246 }
247
248 static int tc358768_probe(struct i2c_client *client,
249                          const struct i2c_device_id *did) 
250 {
251     struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
252     int ret = 0;
253
254     if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
255         dev_warn(&adapter->dev,
256                  "I2C-Adapter doesn't support I2C_FUNC_I2C\n");
257         return -EIO;
258     }
259     
260     tc358768 = (struct tc358768_t *)client->dev.platform_data;
261     if(!tc358768) {
262         ret = -1;
263         printk("%s:%d tc358768 is null\n", __func__, __LINE__);
264         return ret;
265     }   
266
267     tc358768_client = client;
268     if(!tc358768_client) {
269         ret = -1;
270         printk("%s:%d tc358768_client is null\n", __func__, __LINE__);
271         return ret;
272     }
273     
274     if(!tc358768->gpio_init)
275         tc358768->gpio_init = tc358768_gpio_init;
276         
277     if(!tc358768->gpio_deinit)
278         tc358768->gpio_deinit = tc358768_gpio_deinit;    
279     
280     if(!tc358768->power_up)
281         tc358768->power_up = tc358768_power_up;  
282     if(!tc358768->power_down)
283         tc358768->power_down = tc358768_power_down;     
284     
285     if(!tc358768->reset.do_reset)
286         tc358768->reset.do_reset = tc358768_reset;
287     
288     if(!tc358768->vddc.enable)
289         tc358768->vddc.enable = tc358768_vdd_enable;    
290     if(!tc358768->vddc.disable)
291         tc358768->vddc.disable = tc358768_vdd_disable;
292     
293     if(!tc358768->vddio.enable)
294         tc358768->vddio.enable = tc358768_vdd_enable;    
295     if(!tc358768->vddio.disable)
296         tc358768->vddio.disable = tc358768_vdd_disable;
297     
298     if(!tc358768->vdd_mipi.enable)
299         tc358768->vdd_mipi.enable = tc358768_vdd_enable;    
300     if(!tc358768->vdd_mipi.disable)
301         tc358768->vdd_mipi.disable = tc358768_vdd_disable;
302         
303     tc358768_gpio_init(NULL);
304     
305     return ret;
306 }
307 static int tc358768_remove(struct i2c_client *client)
308 {
309     tc358768_gpio_deinit(NULL);
310     tc358768_client = NULL;
311     tc358768 = NULL;
312     return 0;
313 }
314
315 static const struct i2c_device_id tc358768_id[] = {
316         {"tc358768", 0 },
317         { }
318 };
319 MODULE_DEVICE_TABLE(i2c, tc358768_id);
320
321 static struct i2c_driver tc358768_driver = {
322         .probe          = tc358768_probe,
323         .remove         = tc358768_remove,
324         .id_table       = tc358768_id,
325         .driver = {
326                 .name   = "tc358768",
327         },
328 };
329 #else
330
331 u32 spi_read_32bits(u32 addr)
332 {
333         unsigned int i = 32;
334         //a frame starts
335         CS_CLR();
336         CLK_SET();
337
338         addr <<= 16;
339         addr &= 0xfffe0000;
340         addr |= 0x00010000;
341
342         udelay(2);
343         while(i--) {
344                 CLK_CLR();
345                 if(addr & 0x80000000)
346                         TXD_SET();
347         else
348                         TXD_CLR();
349                 addr <<= 1;
350                 udelay(2);
351                 CLK_SET();
352                 udelay(2);
353         }
354         //a frame ends
355     CS_SET();
356
357
358     udelay(2);
359     CS_CLR();
360     addr = 0xfffe0000;
361     i = 16;
362         while(i--) {
363                 CLK_CLR();
364                 if(addr & 0x80000000)
365                         TXD_SET();
366         else
367                         TXD_CLR();
368                 addr <<= 1;
369                 udelay(2);
370                 CLK_SET();
371                 udelay(2);
372         }
373
374         TXD_SET();
375
376         addr = 0;
377     i = 16;
378         while(i--) {
379                 CLK_CLR();
380                 udelay(1);
381                 CLK_SET();
382                 udelay(1);
383                 if (gpio_get_value(gLcd_info->rxd_pin) == 1)
384                         addr |= 1 << i;
385                 udelay(1);
386         }
387     CS_SET();
388
389     return addr;
390 }
391
392
393 //32 bits per frame
394 u32 spi_write_32bits(u32 value)
395 {
396         int i = 32;
397
398     //a frame starts
399         CS_CLR();
400         CLK_SET();
401
402         while(i--) {
403                 CLK_CLR();
404                 if(value & 0x80000000)
405                         TXD_SET();
406         else
407                         TXD_CLR();
408                 value <<= 1;
409                 CLK_SET();
410         }
411         //a frame ends
412     CS_SET();
413
414     return 0;
415 }
416
417 #endif
418
419 u32 tc358768_wr_reg_32bits(u32 data) {
420 #ifdef CONFIG_TC358768_I2C
421         i2c_write_32bits(data);
422 #else
423         spi_write_32bits(data);
424 #endif
425         return 0;
426 }
427
428
429 u32 tc358768_wr_reg_32bits_delay(u32 delay, u32 data) {
430         //wait a minute  according to the source format
431     if(delay < 20000)
432         udelay(delay);
433     else {
434         mdelay(delay/1000);
435     }
436
437 #ifdef CONFIG_TC358768_I2C
438         i2c_write_32bits(data);
439 #else
440         spi_write_32bits(data);
441 #endif
442         return 0;
443 }
444
445
446
447 u32 tc358768_rd_reg_32bits(u32 addr) {
448 #ifdef CONFIG_TC358768_I2C
449         return i2c_read_32bits(addr);
450 #else
451         return spi_read_32bits(addr);
452 #endif
453 }
454
455
456
457 void tc_print(u32 addr) {
458         dsi_debug("+++++++++++addr->%04x: %04x\n", addr, tc358768_rd_reg_32bits(addr));
459 }
460
461 #define tc358768_wr_regs_32bits(reg_array)  _tc358768_wr_regs_32bits(reg_array, ARRAY_SIZE(reg_array))
462 int _tc358768_wr_regs_32bits(unsigned int reg_array[], int n) {
463
464         int i = 0;
465         dsi_debug("%s:%d\n", __func__, n);
466         for(i = 0; i < n; i++) {
467                 if(reg_array[i] < 0x00020000) {
468                     if(reg_array[i] < 20000)
469                         udelay(reg_array[i]);
470                     else {
471                         mdelay(reg_array[i]/1000);
472                     }
473                 } else {
474                         tc358768_wr_reg_32bits(reg_array[i]);
475                 }
476         }
477         return 0;
478 }
479
480 int tc358768_command_tx_less8bytes(unsigned char type, unsigned char *regs, int n) {
481         int i = 0;
482         unsigned int command[] = {
483                         0x06020000,
484                         0x06040000,
485                         0x06100000,
486                         0x06120000,
487                         0x06140000,
488                         0x06160000,
489         };
490
491         if(n <= 2)
492                 command[0] |= 0x1000;   //short packet
493         else {
494                 command[0] |= 0x4000;   //long packet
495                 command[1] |= n;                //word count byte
496         }
497         command[0] |= type;         //data type
498
499         //dsi_debug("*cmd:\n");
500         //dsi_debug("0x%08x\n", command[0]);
501         //dsi_debug("0x%08x\n", command[1]);
502
503         for(i = 0; i < (n + 1)/2; i++) {
504                 command[i+2] |= regs[i*2];
505                 if((i*2 + 1) < n)
506                         command[i+2] |= regs[i*2 + 1] << 8;
507                 dsi_debug("0x%08x\n", command[i+2]);
508         }
509
510         _tc358768_wr_regs_32bits(command, (n + 1)/2 + 2);
511         tc358768_wr_reg_32bits(0x06000001);   //Packet Transfer
512         //wait until packet is out
513         i = 100;
514         while(tc358768_rd_reg_32bits(0x0600) & 0x01) {
515                 if(i-- == 0)
516                         break;
517                 tc_print(0x0600);
518         }
519         //udelay(50);
520         return 0;
521 }
522
523 int tc358768_command_tx_more8bytes_hs(unsigned char type, unsigned char regs[], int n) {
524
525         int i = 0;
526         unsigned int dbg_data = 0x00E80000, temp = 0;
527         unsigned int command[] = {
528                         0x05000080,    //HS data 4 lane, EOT is added
529                         0x0502A300,
530                         0x00080001,
531                         0x00500000,    //Data ID setting
532                         0x00220000,    //Transmission byte count= byte
533                         0x00E08000,        //Enable I2C/SPI write to VB
534                         0x00E20048,    //Total word count = 0x48 (max 0xFFF). This value should be adjusted considering trade off between transmission time and transmission start/stop time delay
535                         0x00E4007F,    //Vertical blank line = 0x7F
536         };
537
538
539         command[3] |= type;        //data type
540         command[4] |= n & 0xffff;           //Transmission byte count
541
542         tc358768_wr_regs_32bits(command);
543
544         for(i = 0; i < (n + 1)/2; i++) {
545                 temp = dbg_data | regs[i*2];
546                 if((i*2 + 1) < n)
547                         temp |= (regs[i*2 + 1] << 8);
548                 //dsi_debug("0x%08x\n", temp);
549                 tc358768_wr_reg_32bits(temp);
550         }
551         if((n % 4 == 1) ||  (n % 4 == 2))     //4 bytes align
552                 tc358768_wr_reg_32bits(dbg_data);
553
554         tc358768_wr_reg_32bits(0x00E0C000);     //Start command transmisison
555         tc358768_wr_reg_32bits(0x00E00000);      //Stop command transmission. This setting should be done just after above setting to prevent multiple output
556         udelay(200);
557         //Re-Initialize
558         //tc358768_wr_regs_32bits(re_initialize);
559         return 0;
560 }
561
562 //low power mode only for tc358768a
563 int tc358768_command_tx_more8bytes_lp(unsigned char type, unsigned char regs[], int n) {
564
565         int i = 0;
566         unsigned int dbg_data = 0x00E80000, temp = 0;
567         unsigned int command[] = {
568                         0x00080001,
569                         0x00500000,    //Data ID setting
570                         0x00220000,    //Transmission byte count= byte
571                         0x00E08000,        //Enable I2C/SPI write to VB
572         };
573
574         command[1] |= type;        //data type
575         command[2] |= n & 0xffff;           //Transmission byte count
576
577         tc358768_wr_regs_32bits(command);
578
579         for(i = 0; i < (n + 1)/2; i++) {
580                 temp = dbg_data | regs[i*2];
581                 if((i*2 + 1) < n)
582                         temp |= (regs[i*2 + 1] << 8);
583                 //dsi_debug("0x%08x\n", temp);
584                 tc358768_wr_reg_32bits(temp);
585
586         }
587         if((n % 4 == 1) ||  (n % 4 == 2))     //4 bytes align
588                 tc358768_wr_reg_32bits(dbg_data);
589
590         tc358768_wr_reg_32bits(0x00E0E000);     //Start command transmisison
591         udelay(1000);
592         tc358768_wr_reg_32bits(0x00E02000);      //Keep Mask High to prevent short packets send out
593         tc358768_wr_reg_32bits(0x00E00000);      //Stop command transmission. This setting should be done just after above setting to prevent multiple output
594         udelay(10);
595         return 0;
596 }
597
598 int _tc358768_send_packet(unsigned char type, unsigned char regs[], int n) {
599
600         if(n <= 8) {
601                 tc358768_command_tx_less8bytes(type, regs, n);
602         } else {
603                 //tc358768_command_tx_more8bytes_hs(type, regs, n);
604                 tc358768_command_tx_more8bytes_lp(type, regs, n);
605         }
606         return 0;
607 }
608
609 int tc358768_send_packet(unsigned char type, unsigned char regs[], int n) {
610         return _tc358768_send_packet(type, regs, n);
611 }
612
613
614 /*
615 The DCS is separated into two functional areas: the User Command Set and the Manufacturer Command
616 Set. Each command is an eight-bit code with 00h to AFh assigned to the User Command Set and all other
617 codes assigned to the Manufacturer Command Set.
618 */
619 int _mipi_dsi_send_dcs_packet(unsigned char regs[], int n) {
620
621         unsigned char type = 0;
622         if(n == 1) {
623                 type = DTYPE_DCS_SWRITE_0P;
624         } else if (n == 2) {
625                 type = DTYPE_DCS_SWRITE_1P;
626         } else if (n > 2) {
627                 type = DTYPE_DCS_LWRITE;
628         } 
629         _tc358768_send_packet(type, regs, n);
630         return 0;
631 }
632
633 int mipi_dsi_send_dcs_packet(unsigned char regs[], int n) {
634         return _mipi_dsi_send_dcs_packet(regs, n);
635 }
636
637
638 int _tc358768_rd_lcd_regs(unsigned char type, char comd, int size, unsigned char* buf) {
639
640         unsigned char regs[8];
641         u32 count = 0, data30, data32;
642         regs[0] = size;
643         regs[1] = 0;
644         tc358768_command_tx_less8bytes(0x37, regs, 2);
645         tc358768_wr_reg_32bits(0x05040010);
646         tc358768_wr_reg_32bits(0x05060000);
647         regs[0] = comd;
648         tc358768_command_tx_less8bytes(type, regs, 1);
649
650         while (!(tc358768_rd_reg_32bits(0x0410) & 0x20)){
651                 printk("error 0x0410:%04x\n", tc358768_rd_reg_32bits(0x0410));
652                 msleep(1);
653                 if(count++ > 10) {
654                         break;
655                 }
656         }
657         
658         data30 = tc358768_rd_reg_32bits(0x0430);          //data id , word count[0:7]
659         //printk("0x0430:%04x\n", data30);
660         data32 = tc358768_rd_reg_32bits(0x0432);          //word count[8:15]  ECC
661         //printk("0x0432:%04x\n", data32);
662         
663         while(size > 0) {
664                 data30 = tc358768_rd_reg_32bits(0x0430);          
665                 //printk("0x0430:%04x\n", data30);
666                 data32 = tc358768_rd_reg_32bits(0x0432);          
667                 //printk("0x0432:%04x\n", data32);
668         
669                 if(size-- > 0)
670                         *buf++ = (u8)data30;
671                 else
672                         break;
673                 if(size-- > 0)
674                         *buf++ = (u8)(data30 >> 8);
675                 else
676                         break;
677                 if(size-- > 0) {
678                         *buf++ = (u8)data32;
679                         if(size-- > 0)
680                                 *buf++ = (u8)(data32 >> 8);
681                 }
682         }       
683         
684         data30 = tc358768_rd_reg_32bits(0x0430);          
685         //printk("0x0430:%04x\n", data30);
686         data32 = tc358768_rd_reg_32bits(0x0432);          
687         //printk("0x0432:%04x\n", data32);
688         return 0;
689 }
690
691 int mipi_dsi_read_dcs_packet(unsigned char *data, int n) {
692         //DCS READ 
693         _tc358768_rd_lcd_regs(0x06, *data, n, data);
694         return 0;
695 }
696
697 int tc358768_get_id(void) {
698         
699         int id = -1;
700         
701         tc358768_power_up();
702         id = tc358768_rd_reg_32bits(0);
703         return id;
704 }
705
706 static struct mipi_dsi_ops tc358768_ops = {
707         .id = 0x4401,
708         .name = "tc358768a",
709         .get_id = tc358768_get_id,
710         .dsi_set_regs = _tc358768_wr_regs_32bits,
711         .dsi_send_dcs_packet = mipi_dsi_send_dcs_packet,
712         .dsi_read_dcs_packet = mipi_dsi_read_dcs_packet,
713         .power_up = tc358768_power_up,
714         .power_down = tc358768_power_down,
715         
716 };
717
718 static int __init tc358768_module_init(void)
719 {
720 #ifdef CONFIG_TC358768_I2C    
721     i2c_add_driver(&tc358768_driver);
722     
723         if(!tc358768 || !tc358768_client)
724                 return -1;
725 #endif          
726                 
727         register_dsi_ops(&tc358768_ops);
728         if(tc358768->id > 0)
729                 tc358768_ops.id = tc358768->id;
730     return 0;
731 }
732
733 static void __exit tc358768_module_exit(void)
734 {
735         del_dsi_ops(&tc358768_ops);
736 #ifdef CONFIG_TC358768_I2C
737         i2c_del_driver(&tc358768_driver);
738 #endif
739 }
740
741 subsys_initcall_sync(tc358768_module_init);
742 //module_exit(tc358768_module_init);
743 module_exit(tc358768_module_exit);