Exemplo n.º 1
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 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;
}