/* ------------------------------------------------------------------------- */ static ssize_t shcamled_torch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { ssize_t ret = -EINVAL; int proc_ret; char *after; unsigned long val = simple_strtoul(buf, &after, 10); size_t count = after - buf; SHCAMLED_TRACE("%s in\n", __FUNCTION__); /* count written bytes size and check size */ if (isspace(*after)) count++; if(count == size) { ret = count; proc_ret = shcamled_pmic_set_torch_led_2_current(val); if(proc_ret) { ret = -EFAULT; SHCAMLED_ERROR("%s failed ret:%d\n", __FUNCTION__, proc_ret); } SHCAMLED_TRACE("%s done ret:%d\n", __FUNCTION__, proc_ret); } SHCAMLED_TRACE("%s done ret:%d\n", __FUNCTION__, ret); return ret; }
/* ------------------------------------------------------------------------- */ static void __exit shcamled_torch_driver_exit(void) { SHCAMLED_TRACE("%s in\n", __FUNCTION__); platform_driver_unregister(&shcamled_torch_driver); platform_device_unregister(&shcamled_torch_dev); SHCAMLED_TRACE("%s done\n", __FUNCTION__); }
int shcamled_pmic_flash_prepare(void) { SHCAMLED_TRACE("%s start\n", __FUNCTION__); mutex_lock(&shcamled_mut); atomic_set(&flash_on_prepare, 1); init_completion(&flash_on_complete); flash_on_thread_active = 1; wake_up_interruptible(&shcamled_msg_on_wait); SHCAMLED_TRACE("%s end\n", __FUNCTION__); return 0; }
/* ------------------------------------------------------------------------- */ static int shcamled_torch_remove(struct platform_device *pdev) { SHCAMLED_TRACE("%s in\n", __FUNCTION__); led_trigger_unregister_simple(cam_torch_led_1_trigger); device_remove_file(&pdev->dev, &dev_attr_shcamled_torch); SHCAMLED_TRACE("%s done\n", __FUNCTION__); return 0; }
/* ------------------------------------------------------------------------- */ int shcamled_pmic_set_torch_led_1_current(unsigned mA) { unsigned int led_current = 0; mutex_lock(&shcamled_torch_mut); SHCAMLED_TRACE("%s in mA:%d ucam:%d ucom:%d\n", __FUNCTION__, mA, shcamled_use_torch_led_cam, shcamled_use_torch_led_comm); if(mA == 0){ if((shcamled_use_torch_led_cam == FALSE && shcamled_use_torch_led_comm == TRUE) || (shcamled_use_torch_led_cam == TRUE && shcamled_use_torch_led_comm == FALSE)) { /* request turning off */ led_trigger_event(cam_torch_led_1_trigger, 0); shcamled_use_torch_led_cam = FALSE; } } else { /* calucurate mA for leds_qpnq */ led_current = mA / 25 /* 12.5 * 2 */; if(led_current > 1){ led_current = led_current - 1; } else { led_current = 0; } led_current = led_current; led_current = (led_current * 200 + 0x0E) / 0x0F; if(led_current < 1){ led_current = 1; } SHCAMLED_TRACE("%s led_current=%d\n", __FUNCTION__, led_current); if(shcamled_use_torch_led_cam == FALSE && shcamled_use_torch_led_comm == FALSE) { /* request turning on */ led_trigger_event(cam_torch_led_1_trigger, led_current); shcamled_use_torch_led_cam = TRUE; } else if(shcamled_use_torch_led_cam == FALSE && shcamled_use_torch_led_comm == TRUE) { /* change user info only */ shcamled_use_torch_led_comm = FALSE; shcamled_use_torch_led_cam = TRUE; } } SHCAMLED_TRACE("%s done ucam:%d ucom:%d\n", __FUNCTION__, shcamled_use_torch_led_cam, shcamled_use_torch_led_comm); mutex_unlock(&shcamled_torch_mut); return 0; }
/* ------------------------------------------------------------------------- */ static int shcamled_torch_probe(struct platform_device *pdev) { int ret; SHCAMLED_TRACE("%s in\n", __FUNCTION__); led_trigger_register_simple("torch_trigger", &cam_torch_led_1_trigger); ret = device_create_file(&pdev->dev, &dev_attr_shcamled_torch); if (ret) { SHCAMLED_ERROR("%s failed create file \n", __FUNCTION__); return ret; } SHCAMLED_TRACE("%s done ret:%d\n", __FUNCTION__, ret); return ret; }
static int flash_on_thread(void * arg) { SHCAMLED_TRACE("%s start\n", __FUNCTION__); while(!kthread_should_stop()){ SHCAMLED_TRACE("%s %d wait_event_interruptible\n", __FUNCTION__, __LINE__); wait_event_interruptible(shcamled_msg_on_wait, kthread_should_stop() || flash_on_thread_active); if(flash_on_thread_active){ SHCAMLED_TRACE("%s %d qpnp_flash_control_enable(true) start\n", __FUNCTION__, __LINE__); // qpnp_flash_control_enable(true); SHCAMLED_TRACE("%s %d qpnp_flash_control_enable(true) end\n", __FUNCTION__, __LINE__); complete(&flash_on_complete); flash_on_thread_active = 0; mutex_unlock(&shcamled_mut); } } SHCAMLED_TRACE("%s end\n", __FUNCTION__); return 0; }
/* ------------------------------------------------------------------------- */ static int flash_off_thread(void * arg) { SHCAMLED_TRACE("%s start\n", __FUNCTION__); while(!kthread_should_stop()){ SHCAMLED_TRACE("%s %d wait_event_interruptible\n", __FUNCTION__, __LINE__); wait_event_interruptible(shcamled_msg_off_wait, kthread_should_stop() || flash_off_thread_active); if(flash_off_thread_active){ SHCAMLED_TRACE("%s %d qpnp_flash_control_enable(false) start\n", __FUNCTION__, __LINE__); qpnp_flash_control_enable(false); SHCAMLED_TRACE("%s %d qpnp_flash_control_enable(false) end\n", __FUNCTION__, __LINE__); flash_off_thread_active = 0; atomic_set(&flash_on_prepare, 0); mutex_unlock(&shcamled_mut); } } SHCAMLED_TRACE("%s end\n", __FUNCTION__); return 0; }
/* ------------------------------------------------------------------------- */ static int shcamled_torch_remove(struct platform_device *pdev) { SHCAMLED_TRACE("%s in\n", __FUNCTION__); led_trigger_unregister_simple(cam_torch_flash_0_trigger); led_trigger_unregister_simple(cam_torch_flash_1_trigger); led_trigger_unregister_simple(cam_torch_led_1_trigger); device_remove_file(&pdev->dev, &dev_attr_shcamled_torch); if(p_flash_off_thread != NULL){ kthread_stop(p_flash_off_thread); } if(p_flash_on_thread != NULL){ kthread_stop(p_flash_on_thread); } SHCAMLED_TRACE("%s done\n", __FUNCTION__); return 0; }
/* ------------------------------------------------------------------------- */ static int __init shcamled_torch_driver_init(void) { int ret; SHCAMLED_TRACE("%s in\n", __FUNCTION__); /* torch 1. register platform-driver for device */ ret = platform_driver_register(&shcamled_torch_driver); if (ret) { SHCAMLED_ERROR("%s failed! L.%d ret=%d\n", __FUNCTION__, __LINE__, ret); return ret; } /* torch 2. register platform-device */ ret = platform_device_register(&shcamled_torch_dev); if (ret) { SHCAMLED_ERROR("%s failed! L.%d ret=%d\n", __FUNCTION__, __LINE__, ret); platform_driver_unregister(&shcamled_torch_driver); return ret; } SHCAMLED_TRACE("%s done\n", __FUNCTION__); return 0; }
/* ------------------------------------------------------------------------- */ static int shcamled_torch_probe(struct platform_device *pdev) { int ret; SHCAMLED_TRACE("%s in\n", __FUNCTION__); led_trigger_register_simple("flash0_trigger", &cam_torch_flash_0_trigger); led_trigger_register_simple("flash1_trigger", &cam_torch_flash_1_trigger); led_trigger_register_simple("torch_trigger", &cam_torch_led_1_trigger); ret = device_create_file(&pdev->dev, &dev_attr_shcamled_torch); if (ret) { SHCAMLED_ERROR("%s failed create file \n", __FUNCTION__); return ret; } init_waitqueue_head(&shcamled_msg_off_wait); init_waitqueue_head(&shcamled_msg_on_wait); p_flash_off_thread = kthread_create(flash_off_thread, &shcamled_mut, "flash_off_thread"); if(p_flash_off_thread != NULL){ wake_up_process(p_flash_off_thread); SHCAMLED_TRACE("%s %d wake_up_process\n", __FUNCTION__, __LINE__); } else { SHCAMLED_TRACE("%s %d p_flash_off_thread =%p\n", __FUNCTION__, __LINE__, p_flash_off_thread); } p_flash_on_thread = kthread_create(flash_on_thread, &shcamled_mut, "flash_on_thread"); if(p_flash_on_thread != NULL){ wake_up_process(p_flash_on_thread); SHCAMLED_TRACE("%s %d wake_up_process\n", __FUNCTION__, __LINE__); } else { SHCAMLED_TRACE("%s %d p_flash_on_thread =%p\n", __FUNCTION__, __LINE__, p_flash_on_thread); } atomic_set(&flash_on_prepare, 0); SHCAMLED_TRACE("%s done ret:%d\n", __FUNCTION__, ret); return ret; }
/* ------------------------------------------------------------------------- */ static int shcamled_pmic_set_torch_led_2_current(unsigned mA) { unsigned int led_current = 0; mutex_lock(&shcamled_torch_mut); SHCAMLED_TRACE("%s in mA:%d ucam:%d ucom:%d\n", __FUNCTION__, mA, shcamled_use_torch_led_cam, shcamled_use_torch_led_comm); if(mA == 0) { if(shcamled_use_torch_led_cam == FALSE && shcamled_use_torch_led_comm == TRUE) { /* request turning off */ if(flash_mode != 0){ led_trigger_event(cam_torch_flash_0_trigger, 0); led_trigger_event(cam_torch_flash_1_trigger, 0); SHCAMLED_TRACE("%s %d wake_up_interruptible start\n", __FUNCTION__, __LINE__); mutex_lock(&shcamled_mut); // qpnp_flash_control_enable(false); if(atomic_read(&flash_on_prepare) == 1){ wait_for_completion(&flash_on_complete); } flash_off_thread_active = 1; wake_up_interruptible(&shcamled_msg_off_wait); SHCAMLED_TRACE("%s %d wake_up_interruptible end\n", __FUNCTION__, __LINE__); flash_mode = 0; } if(torch_mode != 0){ led_trigger_event(cam_torch_led_1_trigger, 0); torch_mode = 0; } shcamled_use_torch_led_comm = FALSE; } } else { /* calucurate mA for leds_qpnq */ led_current = mA / 25 /* 12.5 * 2 */; if(led_current > 1){ led_current = led_current - 1; } else { led_current = 0; } if(mA > 100){ led_current = (led_current * 1000 + 0x4E) / 0x4F; #if defined(CONFIG_ARCH_MSM8226) led_current = SHCAM_LED_FLASH_CURRENT; #endif } else { led_current = (led_current * 200 + 0x0E) / 0x0F; } if(led_current < 1){ led_current = 1; } SHCAMLED_TRACE("%s led_current=%d\n", __FUNCTION__, led_current); if(shcamled_use_torch_led_cam == FALSE && shcamled_use_torch_led_comm == FALSE){ /* request turning on */ if(mA > 100){ if(torch_mode != 0){ led_trigger_event(cam_torch_led_1_trigger, 0); torch_mode = 0; } SHCAMLED_TRACE("%s %d qpnp_flash_control_enable(true) start\n", __FUNCTION__, __LINE__); // qpnp_flash_control_enable(true); if(atomic_read(&flash_on_prepare) == 0){ shcamled_pmic_flash_prepare(); } wait_for_completion(&flash_on_complete); atomic_set(&flash_on_prepare, 0); SHCAMLED_TRACE("%s %d qpnp_flash_control_enable(true) end\n", __FUNCTION__, __LINE__); led_trigger_event(cam_torch_flash_0_trigger, led_current); led_trigger_event(cam_torch_flash_1_trigger, led_current); flash_mode = 1; } else { if(flash_mode != 0){ led_trigger_event(cam_torch_flash_0_trigger, 0); led_trigger_event(cam_torch_flash_1_trigger, 0); SHCAMLED_TRACE("%s %d wake_up_interruptible start\n", __FUNCTION__, __LINE__); mutex_lock(&shcamled_mut); // qpnp_flash_control_enable(false); if(atomic_read(&flash_on_prepare) == 1){ wait_for_completion(&flash_on_complete); } flash_off_thread_active = 1; wake_up_interruptible(&shcamled_msg_off_wait); SHCAMLED_TRACE("%s %d wake_up_interruptible end\n", __FUNCTION__, __LINE__); flash_mode = 0; } led_trigger_event(cam_torch_led_1_trigger, led_current); torch_mode = 1; } shcamled_use_torch_led_comm = TRUE; } } SHCAMLED_TRACE("%s done ucam:%d ucom:%d\n", __FUNCTION__, shcamled_use_torch_led_cam, shcamled_use_torch_led_comm); mutex_unlock(&shcamled_torch_mut); return 0; }