diff options
Diffstat (limited to 'drivers/leds/leds-qpnp-flash-v2.c')
-rw-r--r-- | drivers/leds/leds-qpnp-flash-v2.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index 86e70689ce2d..97d0fccc670f 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -227,6 +227,21 @@ struct flash_switch_data { bool enabled; }; +#ifdef CONFIG_MACH_LONGCHEER +struct flashlight_node_data { + struct platform_device *pdev; + const char **torch_name; + const char **switch_name; + u8 num_torch; + u8 num_switch; + struct led_classdev cdev; + u8 id; + bool led_on; +}; + +#define NAME_SIZE 20 +#endif + /* * Flash LED configuration read from device tree */ @@ -277,11 +292,17 @@ struct qpnp_flash_led { struct regmap *regmap; struct flash_node_data *fnode; struct flash_switch_data *snode; +#ifdef CONFIG_MACH_LONGCHEER + struct flashlight_node_data *flashlight_node; +#endif struct power_supply *bms_psy; struct notifier_block nb; spinlock_t lock; int num_fnodes; int num_snodes; +#ifdef CONFIG_MACH_LONGCHEER + int num_flashlight_nodes; +#endif int enable; int total_current_ma; u16 base; @@ -1338,8 +1359,75 @@ static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev, qpnp_flash_led_node_set(fnode, value); } +#ifdef CONFIG_MACH_LONGCHEER + if (!strcmp("led:switch_0", led_cdev->name) && !value) + if (led->flashlight_node != NULL) + led->flashlight_node->cdev.brightness = value; +#endif + + spin_unlock(&led->lock); +} + +#ifdef CONFIG_MACH_LONGCHEER +static void qpnp_flashlight_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct flashlight_node_data *flashlight_data = NULL; + struct qpnp_flash_led *led = NULL; + int rc; + int i, j; + +#ifdef CONFIG_MACH_XIAOMI_LAVENDER + if (100 == value) + value = 70; +#endif + + if (!strcmp("flashlight", led_cdev->name)) { + flashlight_data = container_of(led_cdev, struct flashlight_node_data, cdev); + led = dev_get_drvdata(&flashlight_data->pdev->dev); + } + + if (!led) { + pr_err("Failed to get flash driver data\n"); + return; + } + + spin_lock(&led->lock); + if (flashlight_data) { + for(i = 0; i < flashlight_data->num_switch; ++i) + for(j = 0; j < led->num_snodes; ++j) { + pr_debug(" switch name[%d] = %s, snode name[%d] = %s\n",i, flashlight_data->switch_name[i],j, led->snode[j].cdev.name); + if (!strcmp(flashlight_data->switch_name[i], led->snode[j].cdev.name)) { + rc = qpnp_flash_led_switch_set(&led->snode[j], false); + if (rc < 0) + pr_err("Failed to set flash LED switch rc=%d\n", rc); + break; + } + } + + for(i = 0; i < flashlight_data->num_torch; ++i) + for(j = 0; j < led->num_fnodes; ++j) { + pr_debug(" torch name[%d] = %s, fnode name[%d] = %s\n",i, flashlight_data->torch_name[i],j, led->fnode[j].cdev.name); + if (!strcmp(flashlight_data->torch_name[i], led->fnode[j].cdev.name)) { + qpnp_flash_led_node_set(&led->fnode[j], value); + break; + } + } + + for(i = 0; i < flashlight_data->num_switch; ++i) + for(j = 0; j < led->num_snodes; ++j) { + pr_debug(" switch name[%d] = %s, snode name[%d] = %s\n",i, flashlight_data->switch_name[i],j, led->snode[j].cdev.name); + if (!strcmp(flashlight_data->switch_name[i], led->snode[j].cdev.name)) { + rc = qpnp_flash_led_switch_set(&led->snode[j], value > 0); + if (rc < 0) + pr_err("Failed to set flash LED switch rc=%d\n", rc); + break; + } + } + } spin_unlock(&led->lock); } +#endif /* sysfs show function for flash_max_current */ static ssize_t qpnp_flash_led_max_current_show(struct device *dev, @@ -1658,6 +1746,11 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, fnode->strobe_ctrl = (hw_strobe << 2) | (edge_trigger << 1) | active_high; +#ifdef CONFIG_MACH_XIAOMI_LAVENDER + if (fnode->type == FLASH_LED_TYPE_TORCH) + fnode->cdev.flags |= LED_KEEP_TRIGGER; +#endif + rc = led_classdev_register(&led->pdev->dev, &fnode->cdev); if (rc < 0) { pr_err("Unable to register led node %d\n", fnode->id); @@ -1707,6 +1800,83 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led, return 0; } +#ifdef CONFIG_MACH_LONGCHEER +static int qpnp_flashlight_led_parse_and_register(struct qpnp_flash_led *led, + struct flashlight_node_data *flashlight_node, struct device_node *node) +{ + int rc,i; + u32 val,count; + const char **temp_name; + + flashlight_node->pdev = led->pdev; + flashlight_node->cdev.brightness_set = qpnp_flashlight_led_brightness_set; + flashlight_node->cdev.brightness_get = qpnp_flash_led_brightness_get; + + rc = of_property_read_string(node, "qcom,led-name", &flashlight_node->cdev.name); + if (rc < 0) { + pr_err("Unable to read flash LED names\n"); + return rc; + } + + count = of_property_count_strings(node, "qcom,torch-name"); + if (!count || (count == -EINVAL)) { + pr_err("%s:%d number of entries is 0 or not present in dts\n", + __func__, __LINE__); + return -EINVAL; + } else + flashlight_node->num_torch = count; + pr_debug("%s qcom,torch-name count %d\n", __func__, flashlight_node->num_torch); + + temp_name = kzalloc(sizeof(char *) * count, GFP_KERNEL); + if (temp_name) { + for(i = 0; i < count; ++i) { + flashlight_node->torch_name = temp_name; + temp_name[i] = kzalloc(sizeof(char) * NAME_SIZE,GFP_KERNEL); + rc = of_property_read_string_index(node,"qcom,torch-name", i,&temp_name[i]); + pr_debug("%s torch_name[%d] = %s\n", __func__, i,flashlight_node->torch_name[i]); + } + } else + pr_err("%s alloc torch_name failed!!!\n",__func__); + + count = of_property_count_strings(node, "qcom,switch-name"); + if (!count || (count == -EINVAL)) { + pr_err("%s:%d number of entries is 0 or not present in dts\n", + __func__, __LINE__); + return -EINVAL; + } else + flashlight_node->num_switch = count; + pr_debug("%s qcom,switch-name count %d\n", __func__, count); + + temp_name = kzalloc(sizeof(char *) * count, GFP_KERNEL); + if (temp_name) { + for(i = 0; i < count; ++i) { + flashlight_node->switch_name = temp_name; + temp_name[i] = kzalloc(sizeof(char) * NAME_SIZE,GFP_KERNEL); + rc = of_property_read_string_index(node,"qcom,switch-name", i,&temp_name[i]); + pr_debug("%s switch_name[%d] = %s\n", __func__, i,flashlight_node->switch_name[i]); + } + } else + pr_err("%s alloc switch_name faild!!!\n",__func__); + + rc = of_property_read_u32(node, "qcom,id", &val); + if (!rc) { + flashlight_node->id = (u8)val; + } else { + pr_err("Unable to read flashlight LED ID\n"); + return rc; + } + + rc = led_classdev_register(&led->pdev->dev, &flashlight_node->cdev); + if (rc < 0) { + pr_err("Unable to register flashlight node %d\n", flashlight_node->id); + return rc; + } + + flashlight_node->cdev.dev->of_node = node; + return 0; +} +#endif + static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led, struct flash_switch_data *snode, struct device_node *node) @@ -2217,6 +2387,9 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) const char *temp_string; unsigned int base; int rc, i = 0, j = 0; +#ifdef CONFIG_MACH_LONGCHEER + int k = 0; +#endif node = pdev->dev.of_node; if (!node) { @@ -2268,6 +2441,10 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) } else if (!strcmp("flash", temp_string) || !strcmp("torch", temp_string)) { led->num_fnodes++; +#ifdef CONFIG_MACH_LONGCHEER + } else if (!strcmp("flashlight", temp_string)) { + led->num_flashlight_nodes++; +#endif } else { pr_err("Invalid label for led node\n"); return -EINVAL; @@ -2291,9 +2468,20 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) if (!led->snode) return -ENOMEM; +#ifdef CONFIG_MACH_LONGCHEER + led->flashlight_node = devm_kcalloc(&pdev->dev, led->num_flashlight_nodes, + sizeof(*led->flashlight_node), + GFP_KERNEL); + if (!led->flashlight_node) + return -ENOMEM; +#endif + temp = NULL; i = 0; j = 0; +#ifdef CONFIG_MACH_LONGCHEER + k = 0; +#endif for_each_available_child_of_node(node, temp) { rc = of_property_read_string(temp, "label", &temp_string); if (rc < 0) { @@ -2323,6 +2511,18 @@ static int qpnp_flash_led_probe(struct platform_device *pdev) } j++; } +#ifdef CONFIG_MACH_LONGCHEER + if (!strcmp("flashlight", temp_string)) { + rc = qpnp_flashlight_led_parse_and_register(led, + &led->flashlight_node[k],temp); + if (rc < 0) { + pr_err("Unable to parse and register flashlight node, rc=%d\n", + rc); + goto error_switch_register; + } + k++; + } +#endif } /* setup irqs */ |