static int qpnp_flash_led_module_disable(struct qpnp_flash_led *led, struct flash_node_data *flash_node) { int rc; u8 val, tmp; rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid, FLASH_LED_STROBE_CTRL(led->base), &val, 1); if (rc) { dev_err(&led->spmi_dev->dev, "Unable to read module enable reg\n"); return -EINVAL; } tmp = ~flash_node->trigger & val; if (!tmp) { 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"); return -EINVAL; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_TORCH(led->base), FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Torch reg write failed\n"); return -EINVAL; } } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_MODULE_ENABLE_CTRL(led->base), FLASH_MODULE_ENABLE_MASK, FLASH_LED_DISABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Module disable failed\n"); return -EINVAL; } } else { rc = qpnp_led_masked_write(led->spmi_dev, FLASH_MODULE_ENABLE_CTRL(led->base), flash_node->enable, flash_node->enable); if (rc) { dev_err(&led->spmi_dev->dev, "Module disable failed\n"); return -EINVAL; } } return 0; }
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 int qpnp_flash_set(struct qpnp_led_data *led) { int rc; int val = led->cdev.brightness; led->flash_cfg->current_prgm = (val * FLASH_MAX_LEVEL / led->max_current); led->flash_cfg->current_prgm = led->flash_cfg->current_prgm >> FLASH_CURRENT_PRGM_SHIFT; if (!led->flash_cfg->current_prgm) led->flash_cfg->current_prgm = FLASH_CURRENT_PRGM_MIN; /* Set led current */ if (val > 0) { 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, led->flash_cfg->second_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_MASK, FLASH_ENABLE_ALL); if (rc) { dev_err(&led->spmi_dev->dev, "Enable reg write failed(%d)\n", rc); return rc; } rc = qpnp_led_masked_write(led, FLASH_LED_STROBE_CTRL(led->base), FLASH_STROBE_MASK, FLASH_STROBE_ALL); if (rc) { dev_err(&led->spmi_dev->dev, "LED %d flash write failed(%d)\n", led->id, rc); return rc; } } else { rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base), FLASH_ENABLE_MASK, FLASH_DISABLE_ALL); if (rc) { dev_err(&led->spmi_dev->dev, "Enable reg write failed(%d)\n", rc); return 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; } } qpnp_dump_regs(led, flash_debug_regs, ARRAY_SIZE(flash_debug_regs)); return 0; }
static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led) { int rc; u8 val, temp_val; rc = qpnp_led_masked_write(led->spmi_dev, FLASH_MODULE_ENABLE_CTRL(led->base), FLASH_MODULE_ENABLE_MASK, FLASH_LED_DISABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Module disable failed\n"); return rc; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_LED_STROBE_CTRL(led->base), FLASH_STROBE_MASK, FLASH_LED_DISABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Strobe disable failed\n"); return rc; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_LED_TMR_CTRL(led->base), FLASH_TMR_MASK, FLASH_TMR_SAFETY); if (rc) { dev_err(&led->spmi_dev->dev, "LED timer ctrl reg write failed(%d)\n", rc); return rc; } val = (u8)(led->pdata->headroom / FLASH_LED_HEADROOM_DIVIDER - FLASH_LED_HEADROOM_OFFSET); rc = qpnp_led_masked_write(led->spmi_dev, FLASH_HEADROOM(led->base), FLASH_HEADROOM_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "Headroom reg write failed\n"); return rc; } val = qpnp_flash_led_get_startup_dly(led->pdata->startup_dly); rc = qpnp_led_masked_write(led->spmi_dev, FLASH_STARTUP_DELAY(led->base), FLASH_STARTUP_DLY_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "Startup delay reg write failed\n"); return rc; } val = (u8)(led->pdata->clamp_current * FLASH_MAX_LEVEL / FLASH_LED_MAX_CURRENT_MA); rc = qpnp_led_masked_write(led->spmi_dev, FLASH_CLAMP_CURRENT(led->base), FLASH_CURRENT_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "Clamp current reg write failed\n"); return rc; } if (led->pdata->pmic_charger_support) val = FLASH_LED_FLASH_HW_VREG_OK; else val = FLASH_LED_FLASH_SW_VREG_OK; rc = qpnp_led_masked_write(led->spmi_dev, FLASH_VREG_OK_FORCE(led->base), FLASH_VREG_OK_FORCE_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "VREG OK force reg write failed\n"); return rc; } if (led->pdata->self_check_en) val = FLASH_MODULE_ENABLE; else val = FLASH_LED_DISABLE; rc = qpnp_led_masked_write(led->spmi_dev, FLASH_FAULT_DETECT(led->base), FLASH_FAULT_DETECT_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "Fault detect reg write failed\n"); return rc; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_MASK_ENABLE(led->base), FLASH_MASK_MODULE_CONTRL_MASK, FLASH_LED_MASK_MODULE_MASK2_ENABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Mask module enable failed\n"); return rc; } if (!led->pdata->thermal_derate_en) val = 0x0; else { val = led->pdata->thermal_derate_en << 7; val |= led->pdata->thermal_derate_rate << 3; val |= (led->pdata->thermal_derate_threshold - FLASH_LED_THERMAL_THRESHOLD_MIN) / FLASH_LED_THERMAL_DEVIDER; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_THERMAL_DRATE(led->base), FLASH_THERMAL_DERATE_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "Thermal derate reg write failed\n"); return rc; } if (!led->pdata->current_ramp_en) val = 0x0; else { val = led->pdata->current_ramp_en << 7; val |= led->pdata->ramp_up_step << 3; val |= led->pdata->ramp_dn_step; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_CURRENT_RAMP(led->base), FLASH_CURRENT_RAMP_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "Current ramp reg write failed\n"); return rc; } if (!led->pdata->vph_pwr_droop_en) val = 0x0; else { val = led->pdata->vph_pwr_droop_en << 7; val |= ((led->pdata->vph_pwr_droop_threshold - FLASH_LED_VPH_DROOP_THRESHOLD_MIN_MV) / FLASH_LED_VPH_DROOP_THRESHOLD_DIVIDER) << 4; temp_val = qpnp_flash_led_get_droop_debounce_time( led->pdata->vph_pwr_droop_debounce_time); if (temp_val == 0xFF) { dev_err(&led->spmi_dev->dev, "Invalid debounce time\n"); return temp_val; } val |= temp_val; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_VPH_PWR_DROOP(led->base), FLASH_VPH_PWR_DROOP_MASK, val); if (rc) { dev_err(&led->spmi_dev->dev, "VPH PWR droop reg write failed\n"); return rc; } if (led->pdata->hdrm_sns_ch0_en) { rc = qpnp_led_masked_write(led->spmi_dev, FLASH_HDRM_SNS_ENABLE_CTRL0(led->base), FLASH_LED_HDRM_SNS_ENABLE_MASK, FLASH_LED_HDRM_SNS_ENABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Headroom sense enable failed\n"); return rc; } } if (led->pdata->hdrm_sns_ch1_en) { rc = qpnp_led_masked_write(led->spmi_dev, FLASH_HDRM_SNS_ENABLE_CTRL1(led->base), FLASH_LED_HDRM_SNS_ENABLE_MASK, FLASH_LED_HDRM_SNS_ENABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Headroom sense enable failed\n"); return rc; } } 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; }
static int qpnp_flash_led_module_disable(struct qpnp_flash_led *led, struct flash_node_data *flash_node) { union power_supply_propval psy_prop; int rc; u8 val, tmp; rc = spmi_ext_register_readl(led->spmi_dev->ctrl, led->spmi_dev->sid, FLASH_LED_STROBE_CTRL(led->base), &val, 1); if (rc) { dev_err(&led->spmi_dev->dev, "Unable to read module enable reg\n"); return -EINVAL; } tmp = ~flash_node->trigger & val; if (!tmp) { 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"); return -EINVAL; } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_TORCH(led->base), FLASH_TORCH_MASK, FLASH_LED_TORCH_DISABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Torch reg write failed\n"); return -EINVAL; } } rc = qpnp_led_masked_write(led->spmi_dev, FLASH_MODULE_ENABLE_CTRL(led->base), FLASH_MODULE_ENABLE_MASK, FLASH_LED_DISABLE); if (rc) { dev_err(&led->spmi_dev->dev, "Module disable failed\n"); return -EINVAL; } if (led->battery_psy) { psy_prop.intval = false; rc = led->battery_psy->set_property(led->battery_psy, POWER_SUPPLY_PROP_FLASH_ACTIVE, &psy_prop); if (rc) { dev_err(&led->spmi_dev->dev, "Failed to setup OTG pulse skip enable\n"); return -EINVAL; } } } else { rc = qpnp_led_masked_write(led->spmi_dev, FLASH_MODULE_ENABLE_CTRL(led->base), flash_node->enable, flash_node->enable); if (rc) { dev_err(&led->spmi_dev->dev, "Module disable failed\n"); return -EINVAL; } } return 0; }