4 * Copyright (c) 2014 Silicon Mitus Co., Ltd
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.
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>
21 #include <linux/workqueue.h>
22 #include <linux/mfd/sprd_sm5701_core.h>
24 //#include <linux/platform_data/leds-sm5701.h>
27 enum sm5701_oper_mode {
31 CHARGING_FLASH_BOOST_MODE
34 struct SM5701_leds_data {
36 struct SM5701_dev *iodev;
38 struct led_classdev cdev_flash;
39 struct led_classdev cdev_movie;
41 struct work_struct work_flash;
42 struct work_struct work_movie;
44 u8 br_flash; //IFLED Current in Flash Mode
45 u8 br_movie; //IMLED Current in Movie Mode
47 //struct sm5701_platform_data *pdata;
52 static struct i2c_client * leds_sm5701_client = NULL;
54 #define ENABSTMR_SHIFT 4
55 void sm5701_set_enabstmr(int abstmr_enable)
57 struct i2c_client * client;
60 client = leds_sm5701_client;
64 pr_info("%s abstmr_enable = %d\n",__func__,abstmr_enable);
66 SM5701_reg_read(client, SM5701_FLEDCNTL1, &data);
68 data = (data & (~SM5701_FLEDCNTL1_ENABSTMR)) | (abstmr_enable << ENABSTMR_SHIFT);
70 SM5701_reg_write(client,SM5701_FLEDCNTL1,data);
72 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL1, data);
75 EXPORT_SYMBOL(sm5701_set_enabstmr);
77 #define ABSTMR_SHIFT 2
78 void sm5701_set_abstmr(int abstmr_sec)
80 struct i2c_client * client;
83 client = leds_sm5701_client;
87 pr_info("%s abstmr_sec = %d\n",__func__,abstmr_sec);
89 SM5701_reg_read(client, SM5701_FLEDCNTL1, &data);
91 data = (data & (~SM5701_FLEDCNTL1_ABSTMR)) | (abstmr_sec << ABSTMR_SHIFT);
93 SM5701_reg_write(client,SM5701_FLEDCNTL1,data);
95 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL1, data);
98 EXPORT_SYMBOL(sm5701_set_abstmr);
100 void sm5701_set_fleden(int fled_enable)
102 struct i2c_client * client;
105 client = leds_sm5701_client;
109 pr_info("%s fled_enable = %d\n",__func__,fled_enable);
111 SM5701_reg_read(client, SM5701_FLEDCNTL1, &data);
113 data = (data & (~SM5701_FLEDCNTL1_FLEDEN)) | fled_enable;
115 SM5701_reg_write(client,SM5701_FLEDCNTL1,data);
117 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL1, data);
120 EXPORT_SYMBOL(sm5701_set_fleden);
122 #define nENSAFET_SHIFT 7
123 void sm5701_set_nensafet(int nensafet_enable)
125 struct i2c_client * client;
128 client = leds_sm5701_client;
132 pr_info("%s nensafet_enable = %d\n",__func__,nensafet_enable);
134 SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
136 data = (data & (~SM5701_FLEDCNTL2_nENSAFET)) | (nensafet_enable << nENSAFET_SHIFT);
138 SM5701_reg_write(client,SM5701_FLEDCNTL2,data);
140 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
143 EXPORT_SYMBOL(sm5701_set_nensafet);
145 #define SAFET_SHIFT 5
146 void sm5701_set_safet(int safet_us)
148 struct i2c_client * client;
151 client = leds_sm5701_client;
155 pr_info("%s safet_us = %d\n",__func__,safet_us);
157 SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
159 data = (data & (~SM5701_FLEDCNTL2_SAFET)) | (safet_us << SAFET_SHIFT);
161 SM5701_reg_write(client,SM5701_FLEDCNTL2,data);
163 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
166 EXPORT_SYMBOL(sm5701_set_safet);
168 #define nONESHOT_SHIFT 4
169 void sm5701_set_noneshot(int noneshot_enable)
171 struct i2c_client * client;
174 client = leds_sm5701_client;
178 pr_info("%s noneshot_enable = %d\n",__func__,noneshot_enable);
180 SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
182 data = (data & (~SM5701_FLEDCNTL2_nONESHOT)) | (noneshot_enable << nONESHOT_SHIFT);
184 SM5701_reg_write(client,SM5701_FLEDCNTL2,data);
186 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
189 EXPORT_SYMBOL(sm5701_set_noneshot);
191 void sm5701_set_onetimer(int onetimer_ms)
193 struct i2c_client * client;
196 client = leds_sm5701_client;
200 pr_info("%s onetimer_ms = %d\n",__func__,onetimer_ms);
202 SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
204 data = (data & (~SM5701_FLEDCNTL2_ONETIMER)) | onetimer_ms;
206 SM5701_reg_write(client,SM5701_FLEDCNTL2,data);
208 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
211 EXPORT_SYMBOL(sm5701_set_onetimer);
213 #define IFLED_MAX 0x1F
214 #define IFLED_MIN 0x0
215 void sm5701_set_ifled(int ifled_ma)
217 struct i2c_client * client;
220 client = leds_sm5701_client;
224 pr_info("%s ifled_ma = %d\n",__func__,ifled_ma);
226 if(ifled_ma < IFLED_MIN)
227 ifled_ma = IFLED_MIN;
228 else if (ifled_ma > IFLED_MAX)
229 ifled_ma = IFLED_MAX;
231 SM5701_reg_read(client, SM5701_FLEDCNTL3, &data);
233 data = (data & (~SM5701_FLEDCNTL3_IFLED)) | ifled_ma;
235 SM5701_reg_write(client,SM5701_FLEDCNTL3,data);
237 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL3, data);
240 EXPORT_SYMBOL(sm5701_set_ifled);
242 #define IMLED_MAX 0x1F
243 #define IMLED_MIN 0x0
244 void sm5701_set_imled(int imled_ma)
246 struct i2c_client * client;
249 client = leds_sm5701_client;
253 pr_info("%s imled_ma = %d\n",__func__,imled_ma);
255 if(imled_ma < IMLED_MIN)
256 imled_ma = IMLED_MIN;
257 else if(imled_ma > IMLED_MAX)
258 imled_ma = IMLED_MAX;
260 SM5701_reg_read(client, SM5701_FLEDCNTL4, &data);
262 data = (data & (~SM5701_FLEDCNTL4_IMLED)) | imled_ma;
264 SM5701_reg_write(client,SM5701_FLEDCNTL4,data);
266 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL4, data);
269 EXPORT_SYMBOL(sm5701_set_imled);
271 #define ENLOWBATT_SHIFT 7
272 void sm5701_set_enlowbatt(int enlowbatt_enable)
274 struct i2c_client * client;
277 client = leds_sm5701_client;
281 pr_info("%s enlowbatt_enable = %d\n",__func__,enlowbatt_enable);
283 SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
285 data = (data & (~SM5701_FLEDCNTL5_ENLOWBATT)) | (enlowbatt_enable << ENLOWBATT_SHIFT);
287 SM5701_reg_write(client,SM5701_FLEDCNTL5,data);
289 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
292 EXPORT_SYMBOL(sm5701_set_enlowbatt);
294 #define LBRSTIMER_SHIFT 5
295 void sm5701_set_lbrstimer(int lbrstimer_us)
297 struct i2c_client * client;
300 client = leds_sm5701_client;
304 pr_info("%s lbrstimer_us = %d\n",__func__,lbrstimer_us);
306 SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
308 data = (data & (~SM5701_FLEDCNTL5_LBRSTIMER)) | (lbrstimer_us << LBRSTIMER_SHIFT);
310 SM5701_reg_write(client,SM5701_FLEDCNTL5,data);
312 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
315 EXPORT_SYMBOL(sm5701_set_lbrstimer);
317 #define LOWBATT_SHIFT 2
318 void sm5701_set_lowbatt(int lowbatt_v)
320 struct i2c_client * client;
323 client = leds_sm5701_client;
327 pr_info("%s lowbatt_v = %d\n",__func__,lowbatt_v);
329 SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
331 data = (data & (~SM5701_FLEDCNTL5_LOWBATT)) | (lowbatt_v << LOWBATT_SHIFT);
333 SM5701_reg_write(client,SM5701_FLEDCNTL5,data);
335 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
338 EXPORT_SYMBOL(sm5701_set_lowbatt);
340 void sm5701_set_lbdhys(int lbdhys_mv)
342 struct i2c_client * client;
345 client = leds_sm5701_client;
349 pr_info("%s lbdhys_mv = %d\n",__func__,lbdhys_mv);
351 SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
353 data = (data & (~SM5701_FLEDCNTL5_LBDHYS))| lbdhys_mv;
355 SM5701_reg_write(client,SM5701_FLEDCNTL5,data);
357 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
360 EXPORT_SYMBOL(sm5701_set_lbdhys);
362 void SM5701_set_bstout(int bstout_mv)
364 struct i2c_client * client;
367 client = leds_sm5701_client;
371 pr_info("%s bstout_mv = %d\n",__func__,bstout_mv);
373 SM5701_reg_read(client, SM5701_FLEDCNTL6, &data);
375 data = (data & (~SM5701_FLEDCNTL6_BSTOUT))| bstout_mv;
377 SM5701_reg_write(client,SM5701_FLEDCNTL6,data);
379 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL6, data);
382 EXPORT_SYMBOL(SM5701_set_bstout);
384 /* brightness control */
385 static int sm5701_brightness_control(struct SM5701_leds_data *chip,
386 u8 brightness, enum sm5701_flash_mode flash_mode)
388 switch (flash_mode) {
393 sm5701_set_ifled(brightness);
394 sm5701_set_fleden(SM5701_FLEDEN_ON_FLASH);
398 sm5701_set_imled(brightness);
399 sm5701_set_fleden(SM5701_FLEDEN_ON_MOVIE);
407 flash_mode = NONE_MODE;
408 sm5701_led_ready(flash_mode);
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)
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);
424 pr_info("%s \n",__func__,*buf);
425 ret = kstrtouint(buf, 10, &state);
430 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
432 sm5701_set_fleden(SM5701_FLEDEN_ON_MOVIE);
434 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
436 //sm5701_dump_register();
441 dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
445 static DEVICE_ATTR(movie, S_IWUSR, NULL, sm5701_movie_store);
447 static void sm5701_deferred_movie_brightness_set(struct work_struct *work)
449 struct SM5701_leds_data *chip =
450 container_of(work, struct SM5701_leds_data, work_movie);
452 mutex_lock(&chip->lock);
453 sm5701_brightness_control(chip, chip->br_movie, MOVIE_MODE);
454 mutex_unlock(&chip->lock);
457 static void sm5701_movie_brightness_set(struct led_classdev *cdev,
458 enum led_brightness brightness)
460 struct SM5701_leds_data *chip =
461 container_of(cdev, struct SM5701_leds_data, cdev_movie);
463 if(brightness >= 0 && brightness <= cdev->max_brightness )
465 chip->br_movie = brightness;
466 schedule_work(&chip->work_movie);
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)
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);
482 pr_info("%s \n",__func__,*buf);
483 ret = kstrtouint(buf, 10, &state);
488 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
490 sm5701_set_fleden(SM5701_FLEDEN_ON_FLASH);
492 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
494 //sm5701_dump_register();
499 dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
503 static DEVICE_ATTR(flash, S_IWUSR, NULL, sm5701_flash_store);
505 static void sm5701_deferred_flash_brightness_set(struct work_struct *work)
507 struct SM5701_leds_data *chip =
508 container_of(work, struct SM5701_leds_data, work_flash);
510 mutex_lock(&chip->lock);
511 sm5701_brightness_control(chip, chip->br_flash, FLASH_MODE);
512 mutex_unlock(&chip->lock);
515 static void sm5701_flash_brightness_set(struct led_classdev *cdev,
516 enum led_brightness brightness)
518 struct SM5701_leds_data *chip =
519 container_of(cdev, struct SM5701_leds_data, cdev_flash);
521 if(brightness >= 0 && brightness <= cdev->max_brightness )
523 chip->br_flash = brightness;
524 schedule_work(&chip->work_flash);
528 /* chip initialize */
529 static int sm5701_chip_init(struct SM5701_leds_data *chip)
533 chip->br_movie = 0x9; //100mA
534 sm5701_set_imled(chip->br_movie);
536 chip->br_flash = 0x0C; //600mA
537 sm5701_set_ifled(chip->br_flash);
539 //sm5701_dump_register();
542 sm5701_set_enabstmr(0);
548 static int leds_sm5701_probe(struct platform_device *pdev)
550 struct SM5701_dev *iodev = dev_get_drvdata(pdev->dev.parent);
551 struct SM5701_leds_data *chip;
555 printk("******* %s *******\n",__func__);
557 chip = kzalloc(sizeof(struct SM5701_leds_data), GFP_KERNEL);
561 chip->dev = &pdev->dev;
563 platform_set_drvdata(pdev, chip);
565 if (!(leds_sm5701_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
568 memset(leds_sm5701_client, 0, sizeof(struct i2c_client));
570 leds_sm5701_client = chip->iodev->i2c;
572 mutex_init(&chip->lock);
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);
584 dev_err(chip->dev, "failed to register flash\n");
585 goto err_create_flash_file;
587 err = device_create_file(chip->cdev_flash.dev, &dev_attr_flash);
589 dev_err(chip->dev, "failed to create flash file\n");
590 goto err_create_flash_pin_file;
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);
602 dev_err(chip->dev, "failed to register movie\n");
603 goto err_create_movie_file;
605 err = device_create_file(chip->cdev_movie.dev, &dev_attr_movie);
607 dev_err(chip->dev, "failed to create movie file\n");
608 goto err_create_movie_pin_file;
611 err = sm5701_chip_init(chip);
615 //sm5701_dump_register();
617 dev_info(chip->dev, "LEDs_SM5701 Probe Done\n");
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);
632 static int leds_sm5701_remove(struct platform_device *pdev)
634 struct SM5701_leds_data *chip = platform_get_drvdata(pdev);
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);
645 static const struct platform_device_id leds_sm5701_id[] = {
650 MODULE_DEVICE_TABLE(platform, leds_sm5701_id);
653 static struct of_device_id leds_sm5701_match_table[] = {
654 { .compatible = "sm,leds_sm5701",},
658 #define SM5701_match_table NULL
661 static struct platform_driver leds_sm5701_driver = {
663 .name = "leds_sm5701",
664 .owner = THIS_MODULE,
665 .of_match_table = leds_sm5701_match_table,
667 .probe = leds_sm5701_probe,
668 .remove = leds_sm5701_remove,
669 .id_table = leds_sm5701_id,
672 static int __init leds_sm5701_init(void)
674 printk("******* %s *******\n",__func__);
676 return platform_driver_register(&leds_sm5701_driver);
679 subsys_initcall(leds_sm5701_init);
681 static void __exit leds_sm5701_exit(void)
683 platform_driver_unregister(&leds_sm5701_driver);
685 module_exit(leds_sm5701_exit);
687 /* Module information */
688 MODULE_DESCRIPTION("SILICONMITUS SM5701 Flash LED Driver");
689 MODULE_LICENSE("GPL");
690 MODULE_ALIAS("platform:leds-sm5701");