video: sprdfd: disable ESD feature
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / leds / leds-sprd-sm5701.c
1 /*
2  * leds-sm5701.c
3  *
4  * Copyright (c) 2014 Silicon Mitus Co., Ltd
5  *
6  *  This program is free software; you can redistribute  it and/or modify it
7  *  under  the terms of  the GNU General  Public License as published by the
8  *  Free Software Foundation;  either version 2 of the  License, or (at your
9  *  option) any later version.
10  *
11  */
12
13 #include <linux/module.h>
14 #include <linux/moduleparam.h>
15 #include <linux/delay.h>
16 #include <linux/i2c.h>
17 #include <linux/leds.h>
18 #include <linux/slab.h>
19 #include <linux/platform_device.h>
20 #include <linux/fs.h>
21 #include <linux/workqueue.h>
22 #include <linux/mfd/sprd_sm5701_core.h>
23
24 //#include <linux/platform_data/leds-sm5701.h>
25
26
27 enum sm5701_oper_mode {
28         SUSPEND_MODE = 0,
29         CHARGING_OFF_MODE,
30         CHARGING_ON_MODE,
31         CHARGING_FLASH_BOOST_MODE
32 };
33
34 struct SM5701_leds_data {
35         struct device *dev;
36         struct SM5701_dev *iodev;
37
38         struct led_classdev cdev_flash;
39         struct led_classdev cdev_movie;
40         
41         struct work_struct work_flash;
42         struct work_struct work_movie;
43
44         u8 br_flash; //IFLED Current in Flash Mode
45         u8 br_movie; //IMLED Current in Movie Mode
46         
47         //struct sm5701_platform_data *pdata;
48
49         struct mutex lock;
50 };
51
52 static struct i2c_client * leds_sm5701_client = NULL;
53
54 #define ENABSTMR_SHIFT  4
55 void sm5701_set_enabstmr(int abstmr_enable)
56 {
57     struct i2c_client * client;
58     u8 data = 0;
59
60     client = leds_sm5701_client;
61   
62     if( !client) return;
63
64     pr_info("%s abstmr_enable = %d\n",__func__,abstmr_enable);
65
66     SM5701_reg_read(client, SM5701_FLEDCNTL1, &data);
67
68     data = (data & (~SM5701_FLEDCNTL1_ENABSTMR)) | (abstmr_enable << ENABSTMR_SHIFT);
69
70     SM5701_reg_write(client,SM5701_FLEDCNTL1,data);    
71   
72     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL1, data);
73     
74 }
75 EXPORT_SYMBOL(sm5701_set_enabstmr);
76
77 #define ABSTMR_SHIFT  2
78 void sm5701_set_abstmr(int abstmr_sec)
79 {
80     struct i2c_client * client;
81     u8 data = 0;
82
83     client = leds_sm5701_client;
84   
85     if( !client) return;
86
87     pr_info("%s abstmr_sec = %d\n",__func__,abstmr_sec);
88
89     SM5701_reg_read(client, SM5701_FLEDCNTL1, &data);
90
91     data = (data & (~SM5701_FLEDCNTL1_ABSTMR)) | (abstmr_sec << ABSTMR_SHIFT);
92
93     SM5701_reg_write(client,SM5701_FLEDCNTL1,data);    
94   
95     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL1, data);
96     
97 }
98 EXPORT_SYMBOL(sm5701_set_abstmr);
99
100 void sm5701_set_fleden(int fled_enable)
101 {
102     struct i2c_client * client;
103     u8 data = 0;
104
105     client = leds_sm5701_client;
106   
107     if( !client) return;
108
109     pr_info("%s fled_enable = %d\n",__func__,fled_enable);
110
111     SM5701_reg_read(client, SM5701_FLEDCNTL1, &data);
112     
113     data = (data & (~SM5701_FLEDCNTL1_FLEDEN)) | fled_enable;
114
115     SM5701_reg_write(client,SM5701_FLEDCNTL1,data);    
116   
117     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL1, data);
118     
119 }
120 EXPORT_SYMBOL(sm5701_set_fleden);
121
122 #define nENSAFET_SHIFT  7
123 void sm5701_set_nensafet(int nensafet_enable)
124 {
125     struct i2c_client * client;
126     u8 data = 0;
127
128     client = leds_sm5701_client;
129   
130     if( !client) return;
131
132     pr_info("%s nensafet_enable = %d\n",__func__,nensafet_enable);
133
134     SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
135
136     data = (data & (~SM5701_FLEDCNTL2_nENSAFET)) | (nensafet_enable << nENSAFET_SHIFT);
137
138     SM5701_reg_write(client,SM5701_FLEDCNTL2,data);    
139   
140     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
141     
142 }
143 EXPORT_SYMBOL(sm5701_set_nensafet);
144
145 #define SAFET_SHIFT  5
146 void sm5701_set_safet(int safet_us)
147 {
148     struct i2c_client * client;
149     u8 data = 0;
150
151     client = leds_sm5701_client;
152   
153     if( !client) return;
154
155     pr_info("%s safet_us = %d\n",__func__,safet_us);
156
157     SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
158
159     data = (data & (~SM5701_FLEDCNTL2_SAFET)) | (safet_us << SAFET_SHIFT);
160
161     SM5701_reg_write(client,SM5701_FLEDCNTL2,data);    
162   
163     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
164     
165 }
166 EXPORT_SYMBOL(sm5701_set_safet);
167
168 #define nONESHOT_SHIFT  4
169 void sm5701_set_noneshot(int noneshot_enable)
170 {
171     struct i2c_client * client;
172     u8 data = 0;
173
174     client = leds_sm5701_client;
175   
176     if( !client) return;
177
178     pr_info("%s noneshot_enable = %d\n",__func__,noneshot_enable);
179
180     SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
181
182     data = (data & (~SM5701_FLEDCNTL2_nONESHOT)) | (noneshot_enable << nONESHOT_SHIFT);
183
184     SM5701_reg_write(client,SM5701_FLEDCNTL2,data);    
185   
186     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
187     
188 }
189 EXPORT_SYMBOL(sm5701_set_noneshot);
190
191 void sm5701_set_onetimer(int onetimer_ms)
192 {
193     struct i2c_client * client;
194     u8 data = 0;
195
196     client = leds_sm5701_client;
197   
198     if( !client) return;
199
200     pr_info("%s onetimer_ms = %d\n",__func__,onetimer_ms);
201
202     SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
203
204     data = (data & (~SM5701_FLEDCNTL2_ONETIMER)) | onetimer_ms;
205
206     SM5701_reg_write(client,SM5701_FLEDCNTL2,data);    
207   
208     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
209     
210 }
211 EXPORT_SYMBOL(sm5701_set_onetimer);
212
213 #define IFLED_MAX   0x1F
214 #define IFLED_MIN   0x0
215 void sm5701_set_ifled(int ifled_ma)
216 {
217     struct i2c_client * client;
218     u8 data = 0;
219
220     client = leds_sm5701_client;
221   
222     if( !client) return;
223
224     pr_info("%s ifled_ma = %d\n",__func__,ifled_ma);
225
226     if(ifled_ma < IFLED_MIN)
227         ifled_ma = IFLED_MIN;
228     else if (ifled_ma > IFLED_MAX)
229         ifled_ma = IFLED_MAX;
230     
231     SM5701_reg_read(client, SM5701_FLEDCNTL3, &data);
232
233     data = (data & (~SM5701_FLEDCNTL3_IFLED)) | ifled_ma;
234
235     SM5701_reg_write(client,SM5701_FLEDCNTL3,data);    
236   
237     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL3, data);
238     
239 }
240 EXPORT_SYMBOL(sm5701_set_ifled);
241
242 #define IMLED_MAX   0x1F
243 #define IMLED_MIN   0x0
244 void sm5701_set_imled(int imled_ma)
245 {
246     struct i2c_client * client;
247     u8 data = 0;
248
249     client = leds_sm5701_client;
250   
251     if( !client) return;
252
253     pr_info("%s imled_ma = %d\n",__func__,imled_ma);
254
255     if(imled_ma < IMLED_MIN) 
256         imled_ma = IMLED_MIN;
257     else if(imled_ma > IMLED_MAX) 
258         imled_ma = IMLED_MAX;
259
260     SM5701_reg_read(client, SM5701_FLEDCNTL4, &data);
261
262     data = (data & (~SM5701_FLEDCNTL4_IMLED)) | imled_ma;
263
264     SM5701_reg_write(client,SM5701_FLEDCNTL4,data);    
265   
266     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL4, data);
267     
268 }
269 EXPORT_SYMBOL(sm5701_set_imled);
270
271 #define ENLOWBATT_SHIFT  7
272 void sm5701_set_enlowbatt(int enlowbatt_enable)
273 {
274     struct i2c_client * client;
275     u8 data = 0;
276
277     client = leds_sm5701_client;
278   
279     if( !client) return;
280
281     pr_info("%s enlowbatt_enable = %d\n",__func__,enlowbatt_enable);
282
283     SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
284
285     data = (data & (~SM5701_FLEDCNTL5_ENLOWBATT)) | (enlowbatt_enable << ENLOWBATT_SHIFT);
286
287     SM5701_reg_write(client,SM5701_FLEDCNTL5,data);    
288   
289     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
290     
291 }
292 EXPORT_SYMBOL(sm5701_set_enlowbatt);
293
294 #define LBRSTIMER_SHIFT  5
295 void sm5701_set_lbrstimer(int lbrstimer_us)
296 {
297     struct i2c_client * client;
298     u8 data = 0;
299
300     client = leds_sm5701_client;
301   
302     if( !client) return;
303
304     pr_info("%s lbrstimer_us = %d\n",__func__,lbrstimer_us);
305
306     SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
307
308     data = (data & (~SM5701_FLEDCNTL5_LBRSTIMER)) | (lbrstimer_us << LBRSTIMER_SHIFT);
309
310     SM5701_reg_write(client,SM5701_FLEDCNTL5,data);    
311   
312     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
313     
314 }
315 EXPORT_SYMBOL(sm5701_set_lbrstimer);
316
317 #define LOWBATT_SHIFT  2
318 void sm5701_set_lowbatt(int lowbatt_v)
319 {
320     struct i2c_client * client;
321     u8 data = 0;
322
323     client = leds_sm5701_client;
324   
325     if( !client) return;
326
327     pr_info("%s lowbatt_v = %d\n",__func__,lowbatt_v);
328
329     SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
330
331     data = (data & (~SM5701_FLEDCNTL5_LOWBATT)) | (lowbatt_v << LOWBATT_SHIFT);
332
333     SM5701_reg_write(client,SM5701_FLEDCNTL5,data);    
334   
335     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
336     
337 }
338 EXPORT_SYMBOL(sm5701_set_lowbatt);
339
340 void sm5701_set_lbdhys(int lbdhys_mv)
341 {
342     struct i2c_client * client;
343     u8 data = 0;
344
345     client = leds_sm5701_client;
346   
347     if( !client) return;
348
349     pr_info("%s lbdhys_mv = %d\n",__func__,lbdhys_mv);
350
351     SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
352
353     data = (data & (~SM5701_FLEDCNTL5_LBDHYS))| lbdhys_mv;
354
355     SM5701_reg_write(client,SM5701_FLEDCNTL5,data);    
356   
357     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
358     
359 }
360 EXPORT_SYMBOL(sm5701_set_lbdhys);
361
362 void SM5701_set_bstout(int bstout_mv)
363 {
364     struct i2c_client * client;
365     u8 data = 0;
366
367     client = leds_sm5701_client;
368   
369     if( !client) return;
370
371     pr_info("%s bstout_mv = %d\n",__func__,bstout_mv);
372
373     SM5701_reg_read(client, SM5701_FLEDCNTL6, &data);
374
375     data = (data & (~SM5701_FLEDCNTL6_BSTOUT))| bstout_mv;
376
377     SM5701_reg_write(client,SM5701_FLEDCNTL6,data);    
378   
379     pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL6, data);
380     
381 }
382 EXPORT_SYMBOL(SM5701_set_bstout);
383
384 /* brightness control */
385 static int sm5701_brightness_control(struct SM5701_leds_data *chip,
386                           u8 brightness, enum sm5701_flash_mode flash_mode)
387 {
388         switch (flash_mode) {
389         case NONE_MODE:
390                 break;
391
392         case FLASH_MODE:            
393                 sm5701_set_ifled(brightness);
394                 sm5701_set_fleden(SM5701_FLEDEN_ON_FLASH);
395                 break;
396
397         case MOVIE_MODE:
398                 sm5701_set_imled(brightness);
399                 sm5701_set_fleden(SM5701_FLEDEN_ON_MOVIE);
400                 break;
401
402         default:
403                 break;
404         }
405         
406         if(0 == brightness)
407                 flash_mode = NONE_MODE;
408         sm5701_led_ready(flash_mode);
409         return flash_mode;
410 }
411
412 /* movie */
413
414 /* movie config for sm5701*/
415 static ssize_t sm5701_movie_store(struct device *dev,
416                                       struct device_attribute *attr,
417                                       const char *buf, size_t size)
418 {
419         ssize_t ret;
420         struct led_classdev *led_cdev = dev_get_drvdata(dev);
421         struct SM5701_leds_data *chip =
422             container_of(led_cdev, struct SM5701_leds_data, work_movie);
423         unsigned int state;
424         pr_info("%s \n",__func__,*buf);
425         ret = kstrtouint(buf, 10, &state);
426         if (ret)
427                 goto out_strtoint;
428         
429         if (state == 0)
430                 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
431         else if (state == 1) 
432                 sm5701_set_fleden(SM5701_FLEDEN_ON_MOVIE);
433         else 
434                 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
435
436         //sm5701_dump_register();
437         
438         return size;
439
440 out_strtoint:
441         dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
442         return ret;
443 }
444
445 static DEVICE_ATTR(movie, S_IWUSR, NULL, sm5701_movie_store);
446
447 static void sm5701_deferred_movie_brightness_set(struct work_struct *work)
448 {
449     struct SM5701_leds_data *chip =
450         container_of(work, struct SM5701_leds_data, work_movie);
451
452         mutex_lock(&chip->lock);
453         sm5701_brightness_control(chip, chip->br_movie, MOVIE_MODE);
454         mutex_unlock(&chip->lock);
455 }
456
457 static void sm5701_movie_brightness_set(struct led_classdev *cdev,
458                                         enum led_brightness brightness)
459 {
460         struct SM5701_leds_data *chip =
461             container_of(cdev, struct SM5701_leds_data, cdev_movie);
462         
463         if(brightness >= 0 && brightness <= cdev->max_brightness )
464         {
465             chip->br_movie = brightness;
466             schedule_work(&chip->work_movie);
467         }
468 }
469
470 /* flash */
471
472 /* flash config for sm5701*/
473 static ssize_t sm5701_flash_store(struct device *dev,
474                                        struct device_attribute *attr,
475                                        const char *buf, size_t size)
476 {
477         ssize_t ret;
478         struct led_classdev *led_cdev = dev_get_drvdata(dev);
479         struct SM5701_leds_data *chip =
480             container_of(led_cdev, struct SM5701_leds_data, work_flash);
481         unsigned int state;
482         pr_info("%s \n",__func__,*buf);
483         ret = kstrtouint(buf, 10, &state);
484         if (ret)
485                 goto out_strtoint;
486         
487         if (state == 0)
488                 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
489         else if (state == 1) 
490                 sm5701_set_fleden(SM5701_FLEDEN_ON_FLASH);
491         else 
492                 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
493
494         //sm5701_dump_register();
495
496         return size;
497         
498 out_strtoint:
499         dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
500         return ret;
501 }
502
503 static DEVICE_ATTR(flash, S_IWUSR, NULL, sm5701_flash_store);
504
505 static void sm5701_deferred_flash_brightness_set(struct work_struct *work)
506 {
507     struct SM5701_leds_data *chip =
508         container_of(work, struct SM5701_leds_data, work_flash);
509     
510         mutex_lock(&chip->lock);
511         sm5701_brightness_control(chip, chip->br_flash, FLASH_MODE);
512         mutex_unlock(&chip->lock);
513 }
514
515 static void sm5701_flash_brightness_set(struct led_classdev *cdev,
516                                          enum led_brightness brightness)
517 {
518         struct SM5701_leds_data *chip =
519             container_of(cdev, struct SM5701_leds_data, cdev_flash);
520
521         if(brightness >= 0 && brightness <= cdev->max_brightness )
522         {
523             chip->br_flash = brightness;
524             schedule_work(&chip->work_flash);
525         }
526 }
527
528 /* chip initialize */
529 static int sm5701_chip_init(struct SM5701_leds_data *chip)
530 {
531         int ret = 0;
532
533         chip->br_movie = 0x9; //100mA
534         sm5701_set_imled(chip->br_movie);
535
536         chip->br_flash = 0x0C; //600mA
537         sm5701_set_ifled(chip->br_flash);
538
539         //sm5701_dump_register();
540
541         //disable ABSTMR
542         sm5701_set_enabstmr(0);
543
544         return ret;
545 }
546
547
548 static int leds_sm5701_probe(struct platform_device *pdev)
549 {
550         struct SM5701_dev *iodev = dev_get_drvdata(pdev->dev.parent);
551         struct SM5701_leds_data *chip;
552
553         int err;
554
555         printk("******* %s *******\n",__func__);
556
557         chip = kzalloc(sizeof(struct SM5701_leds_data), GFP_KERNEL);        
558         if (!chip)
559            return -ENOMEM;
560
561         chip->dev = &pdev->dev;
562         chip->iodev = iodev;
563         platform_set_drvdata(pdev, chip);
564         
565         if (!(leds_sm5701_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
566             return -ENOMEM;
567         }    
568         memset(leds_sm5701_client, 0, sizeof(struct i2c_client));
569
570         leds_sm5701_client = chip->iodev->i2c;    
571
572         mutex_init(&chip->lock);
573
574         /* flash */
575         INIT_WORK(&chip->work_flash, sm5701_deferred_flash_brightness_set);
576         chip->cdev_flash.name = "flash";
577         chip->cdev_flash.max_brightness = 32-1;//0x1f
578         chip->cdev_flash.brightness_set = sm5701_flash_brightness_set;
579         chip->cdev_flash.default_trigger = "flash";
580         err = led_classdev_register((struct device *)
581                                     chip->dev, &chip->cdev_flash);
582
583         if (err < 0) {
584                 dev_err(chip->dev, "failed to register flash\n");
585                 goto err_create_flash_file;
586         }
587         err = device_create_file(chip->cdev_flash.dev, &dev_attr_flash);
588         if (err < 0) {
589                 dev_err(chip->dev, "failed to create flash file\n");
590                 goto err_create_flash_pin_file;
591         }
592
593         /* movie */
594         INIT_WORK(&chip->work_movie, sm5701_deferred_movie_brightness_set);
595         chip->cdev_movie.name = "movie";
596         chip->cdev_movie.max_brightness = 32-1;//0x1f
597         chip->cdev_movie.brightness_set = sm5701_movie_brightness_set;
598         chip->cdev_movie.default_trigger = "movie";
599         err = led_classdev_register((struct device *)
600                                     chip->dev, &chip->cdev_movie);
601         if (err < 0) {
602                 dev_err(chip->dev, "failed to register movie\n");
603                 goto err_create_movie_file;
604         }
605         err = device_create_file(chip->cdev_movie.dev, &dev_attr_movie);
606         if (err < 0) {
607                 dev_err(chip->dev, "failed to create movie file\n");
608                 goto err_create_movie_pin_file;
609         }
610
611         err = sm5701_chip_init(chip);
612         if (err < 0)
613                 goto err_out;
614
615         //sm5701_dump_register();
616
617         dev_info(chip->dev, "LEDs_SM5701 Probe Done\n");
618       return 0;
619
620 err_create_movie_file:
621         device_remove_file(chip->cdev_movie.dev, &dev_attr_movie);
622 err_create_movie_pin_file:
623         led_classdev_unregister(&chip->cdev_movie);
624 err_create_flash_file:
625         device_remove_file(chip->cdev_flash.dev, &dev_attr_flash);
626 err_create_flash_pin_file:
627         led_classdev_unregister(&chip->cdev_flash);
628 err_out:
629         return err;
630 }
631
632 static int leds_sm5701_remove(struct platform_device *pdev)
633 {
634         struct SM5701_leds_data *chip = platform_get_drvdata(pdev);
635
636         device_remove_file(chip->cdev_movie.dev, &dev_attr_movie);
637         led_classdev_unregister(&chip->cdev_movie);
638         flush_work(&chip->work_movie);
639         device_remove_file(chip->cdev_flash.dev, &dev_attr_flash);
640         led_classdev_unregister(&chip->cdev_flash);
641         flush_work(&chip->work_flash);
642         return 0;
643 }
644
645 static const struct platform_device_id leds_sm5701_id[] = {
646         {"leds_sm5701", 0},
647         {}
648 };
649
650 MODULE_DEVICE_TABLE(platform, leds_sm5701_id);
651
652 #ifdef CONFIG_OF
653 static struct of_device_id leds_sm5701_match_table[] = {
654         { .compatible = "sm,leds_sm5701",},
655         {},
656 };
657 #else
658 #define SM5701_match_table NULL
659 #endif
660
661 static struct platform_driver leds_sm5701_driver = {
662         .driver = {
663                    .name = "leds_sm5701",
664                    .owner = THIS_MODULE,
665                    .of_match_table = leds_sm5701_match_table,
666                    },
667         .probe = leds_sm5701_probe,
668         .remove = leds_sm5701_remove,
669         .id_table = leds_sm5701_id,
670 };
671
672 static int __init leds_sm5701_init(void)
673 {
674     printk("******* %s *******\n",__func__);
675
676         return platform_driver_register(&leds_sm5701_driver);
677 }
678
679 subsys_initcall(leds_sm5701_init);
680
681 static void __exit leds_sm5701_exit(void)
682 {
683         platform_driver_unregister(&leds_sm5701_driver);
684 }
685 module_exit(leds_sm5701_exit);
686
687 /* Module information */
688 MODULE_DESCRIPTION("SILICONMITUS SM5701 Flash LED Driver");
689 MODULE_LICENSE("GPL");
690 MODULE_ALIAS("platform:leds-sm5701");
691