static int __devinit qpnp_flash_init(struct qpnp_led_data *led) { int rc; rc = qpnp_led_masked_write(led, FLASH_LED_STROBE_CTRL(led->base), FLASH_STROBE_MASK, FLASH_DISABLE_ALL); if (rc) { dev_err(&led->spmi_dev->dev, "LED %d flash write failed(%d)\n", led->id, rc); return rc; } rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base), FLASH_INIT_MASK, FLASH_ENABLE_MODULE); if (rc) { dev_err(&led->spmi_dev->dev, "Enable reg write failed(%d)\n", rc); return rc; } /* Set flash safety timer */ rc = qpnp_led_masked_write(led, FLASH_SAFETY_TIMER(led->base), FLASH_SAFETY_TIMER_MASK, led->flash_cfg->duration); if (rc) { dev_err(&led->spmi_dev->dev, "Safety timer reg write failed(%d)\n", rc); return rc; } /* Set max current */ rc = qpnp_led_masked_write(led, FLASH_MAX_CURR(led->base), FLASH_CURRENT_MASK, FLASH_MAX_LEVEL); if (rc) { dev_err(&led->spmi_dev->dev, "Max current reg write failed(%d)\n", rc); return rc; } /* Set clamp current */ rc = qpnp_led_masked_write(led, FLASH_CLAMP_CURR(led->base), FLASH_CURRENT_MASK, led->flash_cfg->clamp_curr); if (rc) { dev_err(&led->spmi_dev->dev, "Clamp current reg write failed(%d)\n", rc); return rc; } /* Set timer control - safety or watchdog */ if (led->flash_cfg->safety_timer) rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base), FLASH_TMR_MASK, FLASH_TMR_SAFETY); else rc = qpnp_led_masked_write(led, FLASH_LED_TMR_CTRL(led->base), FLASH_TMR_MASK, FLASH_TMR_WATCHDOG); if (rc) { dev_err(&led->spmi_dev->dev, "LED timer ctrl reg write failed(%d)\n", rc); return rc; } /* Set headroom */ rc = qpnp_led_masked_write(led, FLASH_HEADROOM(led->base), FLASH_HEADROOM_MASK, led->flash_cfg->headroom); if (rc) { dev_err(&led->spmi_dev->dev, "Headroom reg write failed(%d)\n", rc); return rc; } /* Set mask enable */ rc = qpnp_led_masked_write(led, FLASH_MASK_ENABLE(led->base), FLASH_MASK_REG_MASK, FLASH_MASK_1); if (rc) { dev_err(&led->spmi_dev->dev, "Mask enable reg write failed(%d)\n", rc); return rc; } /* Set startup delay */ rc = qpnp_led_masked_write(led, FLASH_STARTUP_DELAY(led->base), FLASH_STARTUP_DLY_MASK, led->flash_cfg->startup_dly); if (rc) { dev_err(&led->spmi_dev->dev, "Startup delay reg write failed(%d)\n", rc); return rc; } rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base), FLASH_VREG_MASK, FLASH_HW_VREG_OK); if (rc) { dev_err(&led->spmi_dev->dev, "Vreg OK reg write failed(%d)\n", rc); return rc; } /* Set led current and enable module */ rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr, FLASH_CURRENT_MASK, led->flash_cfg->current_prgm); if (rc) { dev_err(&led->spmi_dev->dev, "Current reg write failed(%d)\n", rc); return rc; } rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base), FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE); if (rc) { dev_err(&led->spmi_dev->dev, "Enable reg write failed(%d)\n", rc); return rc; } /* dump flash registers */ qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs)); return 0; }
static void qpnp_flash_led_work(struct work_struct *work) { struct flash_node_data *flash_node = container_of(work, struct flash_node_data, work); struct qpnp_flash_led *led = dev_get_drvdata(&flash_node->spmi_dev->dev); int rc, brightness = flash_node->cdev.brightness; int max_curr_avail_ma; u8 val; mutex_lock(&led->flash_led_lock); if (!brightness) goto turn_off; if (brightness < FLASH_LED_MIN_CURRENT_MA) brightness = FLASH_LED_MIN_CURRENT_MA; flash_node->prgm_current = brightness; if (flash_node->boost_regulator && !flash_node->flash_on) { if (regulator_count_voltages(flash_node->boost_regulator) > 0) { rc = regulator_set_voltage(flash_node->boost_regulator, flash_node->boost_voltage_max, flash_node->boost_voltage_max); if (rc) { dev_err(&led->spmi_dev->dev, "boost regulator set voltage failed\n"); mutex_unlock(&led->flash_led_lock); return; } } rc = regulator_enable(flash_node->boost_regulator); if (rc) { dev_err(&led->spmi_dev->dev, "Boost regulator enablement failed\n"); goto error_regulator_enable; } } if (flash_node->type == TORCH) { rc = qpnp_led_masked_write(led->spmi_dev, FLASH_LED_UNLOCK_SECURE(led->base), FLASH_SECURE_MASK, FLASH_UNLOCK_SECURE); if (rc) { dev_err(&led->spmi_dev->dev, "Secure reg write failed\n"); goto exit_flash_led_work; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_TORCH(led->base), FLASH_TORCH_MASK, FLASH_LED_TORCH_ENABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Torch reg write failed\n"); goto exit_flash_led_work; } val = (u8)(flash_node->prgm_current * FLASH_TORCH_MAX_LEVEL / flash_node->max_current); rc = qpnp_led_masked_write(led->spmi_dev, flash_node->current_addr, FLASH_CURRENT_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "Current reg write failed\n"); goto exit_flash_led_work; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_MAX_CURRENT(led->base), FLASH_CURRENT_MASK, FLASH_TORCH_MAX_LEVEL); if (rc) { dev_err(&led->spmi_dev->dev, "Max current reg write failed\n"); goto exit_flash_led_work; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_MODULE_ENABLE_CTRL(led->base), FLASH_MODULE_ENABLE | flash_node->enable, FLASH_MODULE_ENABLE | flash_node->enable); if (rc) { dev_err(&led->spmi_dev->dev, "Module enable reg write failed\n"); goto exit_flash_led_work; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_LED_STROBE_CTRL(led->base), flash_node->trigger, flash_node->trigger); if (rc) { dev_err(&led->spmi_dev->dev, "Strobe ctrl reg write failed\n"); goto exit_flash_led_work; } } else if (flash_node->type == FLASH) { if (led->pdata->power_detect_en) { max_curr_avail_ma = qpnp_flash_led_get_max_avail_current (flash_node, led); if (max_curr_avail_ma < 0) { dev_err(&led->spmi_dev->dev, "Failed to get Max available curr\n"); goto exit_flash_led_work; } else { if (max_curr_avail_ma < flash_node->prgm_current) { dev_err(&led->spmi_dev->dev, "battery only supports %d mA.\n", max_curr_avail_ma); flash_node->prgm_current = (u16) max_curr_avail_ma; } } } val = (u8)((flash_node->duration - FLASH_DURATION_DIVIDER) / FLASH_DURATION_DIVIDER); rc = qpnp_led_masked_write(led->spmi_dev, FLASH_SAFETY_TIMER(led->base), FLASH_SAFETY_TIMER_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "Safety timer reg write failed\n"); goto exit_flash_led_work; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_MAX_CURRENT(led->base), FLASH_CURRENT_MASK, FLASH_MAX_LEVEL); if (rc) { dev_err(&led->spmi_dev->dev, "Max current reg write failed\n"); goto exit_flash_led_work; } val = (u8)(flash_node->prgm_current * FLASH_MAX_LEVEL / flash_node->max_current); rc = qpnp_led_masked_write(led->spmi_dev, flash_node->current_addr, FLASH_CURRENT_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "Current reg write failed\n"); goto exit_flash_led_work; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_MODULE_ENABLE_CTRL(led->base), FLASH_MODULE_ENABLE | flash_node->enable, FLASH_MODULE_ENABLE | flash_node->enable); if (rc) { dev_err(&led->spmi_dev->dev, "Module enable reg write failed\n"); goto exit_flash_led_work; } usleep(FLASH_RAMP_UP_DELAY_US); rc = qpnp_led_masked_write(led->spmi_dev, FLASH_LED_STROBE_CTRL(led->base), flash_node->trigger, flash_node->trigger); if (rc) { dev_err(&led->spmi_dev->dev, "Strobe reg write failed\n"); goto exit_flash_led_work; } } flash_node->flash_on = true; mutex_unlock(&led->flash_led_lock); return; turn_off: rc = qpnp_led_masked_write(led->spmi_dev, FLASH_LED_STROBE_CTRL(led->base), flash_node->trigger, FLASH_LED_DISABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Strobe disable failed\n"); goto exit_flash_led_work; } usleep(FLASH_RAMP_DN_DELAY_US); rc = qpnp_flash_led_module_disable(led, flash_node); if (rc) { dev_err(&led->spmi_dev->dev, "Module disable failed\n"); goto exit_flash_led_work; } exit_flash_led_work: if (flash_node->boost_regulator && flash_node->flash_on) { regulator_disable(flash_node->boost_regulator); error_regulator_enable: if (regulator_count_voltages(flash_node->boost_regulator) > 0) regulator_set_voltage(flash_node->boost_regulator, 0, flash_node->boost_voltage_max); } flash_node->flash_on = false; mutex_unlock(&led->flash_led_lock); return; }