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/sm5701_core.h>
24 #if defined (CONFIG_OF)
25 #include <linux/of_device.h>
27 #include <linux/of_gpio.h>
28 #endif /* CONFIG_OF */
30 //#include <linux/platform_data/leds-sm5701.h>
33 enum sm5701_oper_mode {
37 CHARGING_FLASH_BOOST_MODE
40 struct SM5701_leds_data {
42 struct SM5701_dev *iodev;
44 struct led_classdev cdev_flash;
45 struct led_classdev cdev_movie;
47 struct work_struct work_flash;
48 struct work_struct work_movie;
50 u8 br_flash; //IFLED Current in Flash Mode
51 u8 br_movie; //IMLED Current in Movie Mode
54 unsigned int flashset;
56 //struct sm5701_platform_data *pdata;
61 static struct i2c_client * leds_sm5701_client = NULL;
63 #define ENABSTMR_SHIFT 4
64 void sm5701_set_enabstmr(int abstmr_enable)
66 struct i2c_client * client;
69 client = leds_sm5701_client;
73 pr_info("%s abstmr_enable = %d\n",__func__,abstmr_enable);
75 SM5701_reg_read(client, SM5701_FLEDCNTL1, &data);
77 data = (data & (~SM5701_FLEDCNTL1_ENABSTMR)) | (abstmr_enable << ENABSTMR_SHIFT);
79 SM5701_reg_write(client,SM5701_FLEDCNTL1,data);
81 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL1, data);
84 EXPORT_SYMBOL(sm5701_set_enabstmr);
86 #define ABSTMR_SHIFT 2
87 void sm5701_set_abstmr(int abstmr_sec)
89 struct i2c_client * client;
92 client = leds_sm5701_client;
96 pr_info("%s abstmr_sec = %d\n",__func__,abstmr_sec);
98 SM5701_reg_read(client, SM5701_FLEDCNTL1, &data);
100 data = (data & (~SM5701_FLEDCNTL1_ABSTMR)) | (abstmr_sec << ABSTMR_SHIFT);
102 SM5701_reg_write(client,SM5701_FLEDCNTL1,data);
104 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL1, data);
107 EXPORT_SYMBOL(sm5701_set_abstmr);
109 void sm5701_set_fleden(int fled_enable)
111 struct i2c_client * client;
114 client = leds_sm5701_client;
118 pr_info("%s fled_enable = %d\n",__func__,fled_enable);
120 SM5701_reg_read(client, SM5701_FLEDCNTL1, &data);
122 data = (data & (~SM5701_FLEDCNTL1_FLEDEN)) | fled_enable;
124 SM5701_reg_write(client,SM5701_FLEDCNTL1,data);
126 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL1, data);
129 EXPORT_SYMBOL(sm5701_set_fleden);
131 #define nENSAFET_SHIFT 7
132 void sm5701_set_nensafet(int nensafet_enable)
134 struct i2c_client * client;
137 client = leds_sm5701_client;
141 pr_info("%s nensafet_enable = %d\n",__func__,nensafet_enable);
143 SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
145 data = (data & (~SM5701_FLEDCNTL2_nENSAFET)) | (nensafet_enable << nENSAFET_SHIFT);
147 SM5701_reg_write(client,SM5701_FLEDCNTL2,data);
149 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
152 EXPORT_SYMBOL(sm5701_set_nensafet);
154 #define SAFET_SHIFT 5
155 void sm5701_set_safet(int safet_us)
157 struct i2c_client * client;
160 client = leds_sm5701_client;
164 pr_info("%s safet_us = %d\n",__func__,safet_us);
166 SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
168 data = (data & (~SM5701_FLEDCNTL2_SAFET)) | (safet_us << SAFET_SHIFT);
170 SM5701_reg_write(client,SM5701_FLEDCNTL2,data);
172 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
175 EXPORT_SYMBOL(sm5701_set_safet);
177 #define nONESHOT_SHIFT 4
178 void sm5701_set_noneshot(int noneshot_enable)
180 struct i2c_client * client;
183 client = leds_sm5701_client;
187 pr_info("%s noneshot_enable = %d\n",__func__,noneshot_enable);
189 SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
191 data = (data & (~SM5701_FLEDCNTL2_nONESHOT)) | (noneshot_enable << nONESHOT_SHIFT);
193 SM5701_reg_write(client,SM5701_FLEDCNTL2,data);
195 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
198 EXPORT_SYMBOL(sm5701_set_noneshot);
200 void sm5701_set_onetimer(int onetimer_ms)
202 struct i2c_client * client;
205 client = leds_sm5701_client;
209 pr_info("%s onetimer_ms = %d\n",__func__,onetimer_ms);
211 SM5701_reg_read(client, SM5701_FLEDCNTL2, &data);
213 data = (data & (~SM5701_FLEDCNTL2_ONETIMER)) | onetimer_ms;
215 SM5701_reg_write(client,SM5701_FLEDCNTL2,data);
217 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL2, data);
220 EXPORT_SYMBOL(sm5701_set_onetimer);
222 #define IFLED_MAX 0x1F
223 #define IFLED_MIN 0x0
224 void sm5701_set_ifled(int ifled_ma)
226 struct i2c_client * client;
229 client = leds_sm5701_client;
233 pr_info("%s ifled_ma = %d\n",__func__,ifled_ma);
235 if(ifled_ma < IFLED_MIN)
236 ifled_ma = IFLED_MIN;
237 else if (ifled_ma > IFLED_MAX)
238 ifled_ma = IFLED_MAX;
240 SM5701_reg_read(client, SM5701_FLEDCNTL3, &data);
242 data = (data & (~SM5701_FLEDCNTL3_IFLED)) | ifled_ma;
244 SM5701_reg_write(client,SM5701_FLEDCNTL3,data);
246 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL3, data);
249 EXPORT_SYMBOL(sm5701_set_ifled);
251 #define IMLED_MAX 0x1F
252 #define IMLED_MIN 0x0
253 void sm5701_set_imled(int imled_ma)
255 struct i2c_client * client;
258 client = leds_sm5701_client;
262 pr_info("%s imled_ma = %d\n",__func__,imled_ma);
264 if(imled_ma < IMLED_MIN)
265 imled_ma = IMLED_MIN;
266 else if(imled_ma > IMLED_MAX)
267 imled_ma = IMLED_MAX;
269 SM5701_reg_read(client, SM5701_FLEDCNTL4, &data);
271 data = (data & (~SM5701_FLEDCNTL4_IMLED)) | imled_ma;
273 SM5701_reg_write(client,SM5701_FLEDCNTL4,data);
275 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL4, data);
278 EXPORT_SYMBOL(sm5701_set_imled);
280 #define ENLOWBATT_SHIFT 7
281 void sm5701_set_enlowbatt(int enlowbatt_enable)
283 struct i2c_client * client;
286 client = leds_sm5701_client;
290 pr_info("%s enlowbatt_enable = %d\n",__func__,enlowbatt_enable);
292 SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
294 data = (data & (~SM5701_FLEDCNTL5_ENLOWBATT)) | (enlowbatt_enable << ENLOWBATT_SHIFT);
296 SM5701_reg_write(client,SM5701_FLEDCNTL5,data);
298 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
301 EXPORT_SYMBOL(sm5701_set_enlowbatt);
303 #define LBRSTIMER_SHIFT 5
304 void sm5701_set_lbrstimer(int lbrstimer_us)
306 struct i2c_client * client;
309 client = leds_sm5701_client;
313 pr_info("%s lbrstimer_us = %d\n",__func__,lbrstimer_us);
315 SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
317 data = (data & (~SM5701_FLEDCNTL5_LBRSTIMER)) | (lbrstimer_us << LBRSTIMER_SHIFT);
319 SM5701_reg_write(client,SM5701_FLEDCNTL5,data);
321 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
324 EXPORT_SYMBOL(sm5701_set_lbrstimer);
326 #define LOWBATT_SHIFT 2
327 void sm5701_set_lowbatt(int lowbatt_v)
329 struct i2c_client * client;
332 client = leds_sm5701_client;
336 pr_info("%s lowbatt_v = %d\n",__func__,lowbatt_v);
338 SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
340 data = (data & (~SM5701_FLEDCNTL5_LOWBATT)) | (lowbatt_v << LOWBATT_SHIFT);
342 SM5701_reg_write(client,SM5701_FLEDCNTL5,data);
344 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
347 EXPORT_SYMBOL(sm5701_set_lowbatt);
349 void sm5701_set_lbdhys(int lbdhys_mv)
351 struct i2c_client * client;
354 client = leds_sm5701_client;
358 pr_info("%s lbdhys_mv = %d\n",__func__,lbdhys_mv);
360 SM5701_reg_read(client, SM5701_FLEDCNTL5, &data);
362 data = (data & (~SM5701_FLEDCNTL5_LBDHYS))| lbdhys_mv;
364 SM5701_reg_write(client,SM5701_FLEDCNTL5,data);
366 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL5, data);
369 EXPORT_SYMBOL(sm5701_set_lbdhys);
371 void SM5701_set_bstout(int bstout_mv)
373 struct i2c_client * client;
376 client = leds_sm5701_client;
380 pr_info("%s bstout_mv = %d\n",__func__,bstout_mv);
382 SM5701_reg_read(client, SM5701_FLEDCNTL6, &data);
384 data = (data & (~SM5701_FLEDCNTL6_BSTOUT))| bstout_mv;
386 SM5701_reg_write(client,SM5701_FLEDCNTL6,data);
388 pr_info("write SM5701 addr : 0x%02x data : 0x%02x\n", SM5701_FLEDCNTL6, data);
391 EXPORT_SYMBOL(SM5701_set_bstout);
393 /* brightness control */
394 static int sm5701_brightness_control(struct SM5701_leds_data *chip,
395 u8 brightness, enum sm5701_flash_mode flash_mode)
397 switch (flash_mode) {
402 sm5701_set_ifled(brightness);
406 sm5701_set_imled(brightness);
418 /* movie config for sm5701*/
419 static ssize_t sm5701_movie_store(struct device *dev,
420 struct device_attribute *attr,
421 const char *buf, size_t size)
424 struct led_classdev *led_cdev = dev_get_drvdata(dev);
425 struct SM5701_leds_data *chip =
426 container_of(led_cdev, struct SM5701_leds_data, work_movie);
429 ret = kstrtouint(buf, 10, &state);
434 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
436 sm5701_set_fleden(SM5701_FLEDEN_ON_MOVIE);
438 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
440 //sm5701_dump_register();
445 dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
449 static DEVICE_ATTR(movie, S_IWUSR, NULL, sm5701_movie_store);
451 static void sm5701_deferred_movie_brightness_set(struct work_struct *work)
453 struct SM5701_leds_data *chip =
454 container_of(work, struct SM5701_leds_data, work_movie);
456 mutex_lock(&chip->lock);
457 sm5701_brightness_control(chip, chip->br_movie, MOVIE_MODE);
458 mutex_unlock(&chip->lock);
461 static void sm5701_movie_brightness_set(struct led_classdev *cdev,
462 enum led_brightness brightness)
464 struct SM5701_leds_data *chip =
465 container_of(cdev, struct SM5701_leds_data, cdev_movie);
467 if(brightness >= 0 && brightness <= cdev->max_brightness )
469 chip->br_movie = brightness;
470 schedule_work(&chip->work_movie);
476 /* flash config for sm5701*/
477 static ssize_t sm5701_flash_store(struct device *dev,
478 struct device_attribute *attr,
479 const char *buf, size_t size)
482 struct led_classdev *led_cdev = dev_get_drvdata(dev);
483 struct SM5701_leds_data *chip =
484 container_of(led_cdev, struct SM5701_leds_data, work_flash);
487 ret = kstrtouint(buf, 10, &state);
492 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
494 sm5701_set_fleden(SM5701_FLEDEN_ON_FLASH);
496 sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
498 //sm5701_dump_register();
503 dev_err(chip->dev, "%s: fail to change str to int\n", __func__);
507 static DEVICE_ATTR(flash, S_IWUSR, NULL, sm5701_flash_store);
509 static void sm5701_deferred_flash_brightness_set(struct work_struct *work)
511 struct SM5701_leds_data *chip =
512 container_of(work, struct SM5701_leds_data, work_flash);
514 mutex_lock(&chip->lock);
515 sm5701_brightness_control(chip, chip->br_flash, FLASH_MODE);
516 mutex_unlock(&chip->lock);
519 static void sm5701_flash_brightness_set(struct led_classdev *cdev,
520 enum led_brightness brightness)
522 struct SM5701_leds_data *chip =
523 container_of(cdev, struct SM5701_leds_data, cdev_flash);
525 if(brightness >= 0 && brightness <= cdev->max_brightness )
527 chip->br_flash = brightness;
528 schedule_work(&chip->work_flash);
532 /* chip initialize */
533 static int sm5701_chip_init(struct SM5701_leds_data *chip)
537 chip->br_movie = 0x0E; //150mA
538 sm5701_set_imled(chip->br_movie);
540 chip->br_flash = 0x19; //1200mA
541 sm5701_set_ifled(chip->br_flash);
543 //sm5701_dump_register();
546 sm5701_set_enabstmr(0);
551 static int sm5701_leds_parse_dt(struct SM5701_leds_data *chip)
553 struct device_node *np = of_find_node_by_name(NULL, "leds_sm5701");
557 pr_err("%s np NULL\n", __func__);
560 chip->flashen = of_get_named_gpio(np, "flashen-gpio", 0);
561 chip->flashset = of_get_named_gpio(np, "flashtorch-gpio", 0);
563 pr_info("%s: SM5701_parse_dt flashen: %d\n", __func__, chip->flashen);
564 pr_info("%s: SM5701_parse_dt flashset: %d\n", __func__, chip->flashset);
566 ret = gpio_request(chip->flashen, NULL);
568 printk(KERN_WARNING"[FLASH] FLASHEN request failed.%d\n", ret);
570 gpio_direction_output(chip->flashen, 0);
572 ret = gpio_request(chip->flashset, NULL);
574 printk(KERN_WARNING"[FLASH] FLASHSET %d\n", ret);
576 gpio_direction_output(chip->flashset, 0);
582 static int leds_sm5701_probe(struct platform_device *pdev)
584 struct SM5701_dev *iodev = dev_get_drvdata(pdev->dev.parent);
585 struct SM5701_leds_data *chip;
589 printk("******* %s *******\n",__func__);
591 chip = kzalloc(sizeof(struct SM5701_leds_data), GFP_KERNEL);
595 chip->dev = &pdev->dev;
597 platform_set_drvdata(pdev, chip);
599 #if 0 //Prevent Issue : 34260
600 if (!(leds_sm5701_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
603 memset(leds_sm5701_client, 0, sizeof(struct i2c_client));
606 leds_sm5701_client = chip->iodev->i2c;
608 mutex_init(&chip->lock);
611 INIT_WORK(&chip->work_flash, sm5701_deferred_flash_brightness_set);
612 chip->cdev_flash.name = "flash";
613 chip->cdev_flash.max_brightness = 32-1;//0x1f
614 chip->cdev_flash.brightness_set = sm5701_flash_brightness_set;
615 chip->cdev_flash.default_trigger = "flash";
616 err = led_classdev_register((struct device *)
617 chip->dev, &chip->cdev_flash);
620 dev_err(chip->dev, "failed to register flash\n");
621 goto err_create_flash_file;
623 err = device_create_file(chip->cdev_flash.dev, &dev_attr_flash);
625 dev_err(chip->dev, "failed to create flash file\n");
626 goto err_create_flash_pin_file;
630 INIT_WORK(&chip->work_movie, sm5701_deferred_movie_brightness_set);
631 chip->cdev_movie.name = "movie";
632 chip->cdev_movie.max_brightness = 32-1;//0x1f
633 chip->cdev_movie.brightness_set = sm5701_movie_brightness_set;
634 chip->cdev_movie.default_trigger = "movie";
635 err = led_classdev_register((struct device *)
636 chip->dev, &chip->cdev_movie);
638 dev_err(chip->dev, "failed to register movie\n");
639 goto err_create_movie_file;
641 err = device_create_file(chip->cdev_movie.dev, &dev_attr_movie);
643 dev_err(chip->dev, "failed to create movie file\n");
644 goto err_create_movie_pin_file;
647 err = sm5701_chip_init(chip);
651 //sm5701_dump_register();
653 /* To control FLED releated GPIOs */
654 err = sm5701_leds_parse_dt(chip);
656 dev_err(chip->dev, "Failed to control GPIOs\n");
658 dev_info(chip->dev, "LEDs_SM5701 Probe Done\n");
662 err_create_movie_file:
663 device_remove_file(chip->cdev_movie.dev, &dev_attr_movie);
664 err_create_movie_pin_file:
665 led_classdev_unregister(&chip->cdev_movie);
666 err_create_flash_file:
667 device_remove_file(chip->cdev_flash.dev, &dev_attr_flash);
668 err_create_flash_pin_file:
669 led_classdev_unregister(&chip->cdev_flash);
674 static int leds_sm5701_remove(struct platform_device *pdev)
676 struct SM5701_leds_data *chip = platform_get_drvdata(pdev);
678 device_remove_file(chip->cdev_movie.dev, &dev_attr_movie);
679 led_classdev_unregister(&chip->cdev_movie);
680 flush_work(&chip->work_movie);
681 device_remove_file(chip->cdev_flash.dev, &dev_attr_flash);
682 led_classdev_unregister(&chip->cdev_flash);
683 flush_work(&chip->work_flash);
687 static const struct platform_device_id leds_sm5701_id[] = {
692 MODULE_DEVICE_TABLE(platform, leds_sm5701_id);
695 static struct of_device_id leds_sm5701_match_table[] = {
696 { .compatible = "sm,leds_sm5701",},
700 #define SM5701_match_table NULL
703 static struct platform_driver leds_sm5701_driver = {
705 .name = "leds_sm5701",
706 .owner = THIS_MODULE,
707 .of_match_table = leds_sm5701_match_table,
709 .probe = leds_sm5701_probe,
710 .remove = leds_sm5701_remove,
711 .id_table = leds_sm5701_id,
714 static int __init leds_sm5701_init(void)
716 printk("******* %s *******\n",__func__);
718 return platform_driver_register(&leds_sm5701_driver);
721 subsys_initcall(leds_sm5701_init);
723 static void __exit leds_sm5701_exit(void)
725 platform_driver_unregister(&leds_sm5701_driver);
727 module_exit(leds_sm5701_exit);
729 /* Module information */
730 MODULE_DESCRIPTION("SILICONMITUS SM5701 Flash LED Driver");
731 MODULE_LICENSE("GPL");
732 MODULE_ALIAS("platform:leds-sm5701");