예제 #1
0
static void voltage_to_req(int uV, struct vreg *vreg)
{
	if (vreg->part->uV.mask)
		SET_PART(vreg, uV, uV);
	else if (vreg->part->mV.mask)
		SET_PART(vreg, mV, MICRO_TO_MILLI(uV));
	else if (vreg->part->enable_state.mask)
		SET_PART(vreg, enable_state, uV);
	else
		SET_PART(vreg, mV, MICRO_TO_MILLI(uV));
}
static void set_enable(struct vreg *vreg, unsigned int *mask, unsigned int *val)
{
	switch (vreg->type) {
	case RPM_REGULATOR_TYPE_LDO:
	case RPM_REGULATOR_TYPE_SMPS:
		/* Enable by setting a voltage. */
		if (vreg->part->uV.mask) {
			val[vreg->part->uV.word]
				|= vreg->save_uV << vreg->part->uV.shift;
			mask[vreg->part->uV.word] |= vreg->part->uV.mask;
		} else {
			val[vreg->part->mV.word]
				|= MICRO_TO_MILLI(vreg->save_uV)
					<< vreg->part->mV.shift;
			mask[vreg->part->mV.word] |= vreg->part->mV.mask;
		}
		break;
	case RPM_REGULATOR_TYPE_VS:
	case RPM_REGULATOR_TYPE_NCP:
		/* Enable by setting enable_state. */
		val[vreg->part->enable_state.word]
			|= RPM_VREG_STATE_ON << vreg->part->enable_state.shift;
		mask[vreg->part->enable_state.word]
			|= vreg->part->enable_state.mask;
	}
}
예제 #3
0
int main(int argc, char* argv[]){

    if(argc==1){
        printUsage(argv[0]);
        exit(-1);
    }

    char options[]="l:t:h";
    int flag;
    unsigned int blinks=3;
    float timeout=MICRO_TO_MILLI(20.0f);

    while((flag=getopt(argc, argv, options)) != -1){
        switch(flag){
            case 'h':
                printUsage(argv[0]);
                exit(-1);
            case 'l':
                blinks=atoi(optarg);
                break;
            case 't':
                timeout=MICRO_TO_MILLI(atof(optarg));
                break;
            case '?':
                printUsage(argv[0]);
                exit(-1);
            default:
                printUsage(argv[0]);
                exit(-1);
        }
    }

    int i=0;
    for(i=0; blinks>i; i++){
        writeToFile(&LIGHT_ON);
        //printf("on\n");
        usleep(timeout);
        writeToFile(&LIGHT_OFF);
        //printf("off\n");
        usleep(timeout);
    }
    //fclose(filePtr);
}
static unsigned int vreg_get_optimum_mode(struct regulator_dev *rdev,
			int input_uV, int output_uV, int load_uA)
{
	struct vreg *vreg = rdev_get_drvdata(rdev);
	unsigned int mode;

	load_uA += vreg->pdata.system_uA;

	mutex_lock(&vreg->pc_lock);
	SET_PART(vreg, ip, MICRO_TO_MILLI(saturate_peak_load(vreg, load_uA)));
	if (config->ia_follows_ip)
		SET_PART(vreg, ia,
			 MICRO_TO_MILLI(saturate_avg_load(vreg, load_uA)));
	mutex_unlock(&vreg->pc_lock);

	if (load_uA >= vreg->hpm_min_load)
		mode = config->mode_hpm;
	else
		mode = config->mode_lpm;

	return mode;
}
static unsigned int vreg_legacy_get_optimum_mode(struct regulator_dev *rdev,
			int input_uV, int output_uV, int load_uA)
{
	struct vreg *vreg = rdev_get_drvdata(rdev);

	if (MICRO_TO_MILLI(load_uA) <= 0) {
		/*
		 * vreg_legacy_get_optimum_mode is being called before consumers
		 * have specified their load currents via
		 * regulator_set_optimum_mode. Return whatever the existing mode
		 * is.
		 */
		return vreg->mode;
	}

	return vreg_get_optimum_mode(rdev, input_uV, output_uV, load_uA);
}
static int vreg_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
	struct vreg *vreg = rdev_get_drvdata(rdev);
	unsigned int mask[2] = {0}, val[2] = {0};
	int rc = 0;
	int peak_uA;

	mutex_lock(&vreg->pc_lock);

	peak_uA = MILLI_TO_MICRO((vreg->req[vreg->part->ip.word].value
				& vreg->part->ip.mask) >> vreg->part->ip.shift);

	if (mode == config->mode_hpm) {
		/* Make sure that request currents are in HPM range. */
		if (peak_uA < vreg_hpm_min_uA(vreg)) {
			val[vreg->part->ip.word]
				= MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
					<< vreg->part->ip.shift;
			mask[vreg->part->ip.word] = vreg->part->ip.mask;

			if (config->ia_follows_ip) {
				val[vreg->part->ia.word]
					|= MICRO_TO_MILLI(vreg_hpm_min_uA(vreg))
						<< vreg->part->ia.shift;
				mask[vreg->part->ia.word]
					|= vreg->part->ia.mask;
			}
		}
	} else if (mode == config->mode_lpm) {
		/* Make sure that request currents are in LPM range. */
		if (peak_uA > vreg_lpm_max_uA(vreg)) {
			val[vreg->part->ip.word]
				= MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
					<< vreg->part->ip.shift;
			mask[vreg->part->ip.word] = vreg->part->ip.mask;

			if (config->ia_follows_ip) {
				val[vreg->part->ia.word]
					|= MICRO_TO_MILLI(vreg_lpm_max_uA(vreg))
						<< vreg->part->ia.shift;
				mask[vreg->part->ia.word]
					|= vreg->part->ia.mask;
			}
		}
	} else {
		vreg_err(vreg, "invalid mode: %u\n", mode);
		mutex_unlock(&vreg->pc_lock);
		return -EINVAL;
	}

	if (vreg->is_enabled) {
		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
					vreg->part->request_len);
	} else {
		/* Regulator is disabled; store but don't send new request. */
		rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
	}

	if (rc)
		vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
	else
		vreg->mode = mode;

	mutex_unlock(&vreg->pc_lock);

	return rc;
}
static int vreg_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
			    unsigned *selector)
{
	struct vreg *vreg = rdev_get_drvdata(rdev);
	struct vreg_range *range = &vreg->set_points->range[0];
	unsigned int mask[2] = {0}, val[2] = {0};
	int rc = 0, uV = min_uV;
	int lim_min_uV, lim_max_uV, i;

	/* Check if request voltage is outside of physically settable range. */
	lim_min_uV = vreg->set_points->range[0].min_uV;
	lim_max_uV =
		vreg->set_points->range[vreg->set_points->count - 1].max_uV;

	if (uV < lim_min_uV && max_uV >= lim_min_uV)
		uV = lim_min_uV;

	if (uV < lim_min_uV || uV > lim_max_uV) {
		vreg_err(vreg,
			"request v=[%d, %d] is outside possible v=[%d, %d]\n",
			 min_uV, max_uV, lim_min_uV, lim_max_uV);
		return -EINVAL;
	}

	/* Find the range which uV is inside of. */
	for (i = vreg->set_points->count - 1; i > 0; i--) {
		if (uV > vreg->set_points->range[i - 1].max_uV) {
			range = &vreg->set_points->range[i];
			break;
		}
	}

	/*
	 * Force uV to be an allowed set point and apply a ceiling function
	 * to non-set point values.
	 */
	uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
	uV = uV * range->step_uV + range->min_uV;

	if (uV > max_uV) {
		vreg_err(vreg,
			"request v=[%d, %d] cannot be met by any set point; "
			"next set point: %d\n",
			min_uV, max_uV, uV);
		return -EINVAL;
	}

	if (vreg->part->uV.mask) {
		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
		mask[vreg->part->uV.word] = vreg->part->uV.mask;
	} else {
		val[vreg->part->mV.word]
			= MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
		mask[vreg->part->mV.word] = vreg->part->mV.mask;
	}

	mutex_lock(&vreg->pc_lock);

	/*
	 * Only send a request for a new voltage if the regulator is currently
	 * enabled.  This will ensure that LDO and SMPS regulators are not
	 * inadvertently turned on because voltage > 0 is equivalent to
	 * enabling.  For NCP, this just removes unnecessary RPM requests.
	 */
	if (vreg->is_enabled) {
		rc = vreg_set(vreg, mask[0], val[0], mask[1], val[1],
				vreg->part->request_len);
		if (rc)
			vreg_err(vreg, "vreg_set failed, rc=%d\n", rc);
	} else if (vreg->type == RPM_REGULATOR_TYPE_NCP) {
		/* Regulator is disabled; store but don't send new request. */
		rc = vreg_store(vreg, mask[0], val[0], mask[1], val[1]);
	}

	if (!rc && (!vreg->pdata.sleep_selectable || !vreg->is_enabled))
		vreg->save_uV = uV;

	mutex_unlock(&vreg->pc_lock);

	return rc;
}
/**
 * rpm_vreg_set_voltage - vote for a min_uV value of specified regualtor
 * @vreg: ID for regulator
 * @voter: ID for the voter
 * @min_uV: minimum acceptable voltage (in uV) that is voted for
 * @max_uV: maximum acceptable voltage (in uV) that is voted for
 * @sleep_also: 0 for active set only, non-0 for active set and sleep set
 *
 * Returns 0 on success or errno.
 *
 * This function is used to vote for the voltage of a regulator without
 * using the regulator framework.  It is needed by consumers which hold spin
 * locks or have interrupts disabled because the regulator framework can sleep.
 * It is also needed by consumers which wish to only vote for active set
 * regulator voltage.
 *
 * If sleep_also == 0, then a sleep-set value of 0V will be voted for.
 *
 * This function may only be called for regulators which have the sleep flag
 * specified in their private data.
 *
 * Consumers can vote to disable a regulator with this function by passing
 * min_uV = 0 and max_uV = 0.
 */
int rpm_vreg_set_voltage(int vreg_id, enum rpm_vreg_voter voter, int min_uV,
			 int max_uV, int sleep_also)
{
	unsigned int mask[2] = {0}, val[2] = {0};
	struct vreg_range *range;
	struct vreg *vreg;
	int uV = min_uV;
	int lim_min_uV, lim_max_uV, i, rc;

	/*
	 * HACK: make this function a no-op for 8064 so that it can be called by
	 * consumers on 8064 before RPM capabilities are present. (needed for
	 * acpuclock driver)
	 */
	if (cpu_is_apq8064())
		return 0;

	if (!config) {
		pr_err("rpm-regulator driver has not probed yet.\n");
		return -ENODEV;
	}

	if (vreg_id < config->vreg_id_min || vreg_id > config->vreg_id_max) {
		pr_err("invalid regulator id=%d\n", vreg_id);
		return -EINVAL;
	}

	vreg = &config->vregs[vreg_id];
	range = &vreg->set_points->range[0];

	if (!vreg->pdata.sleep_selectable) {
		vreg_err(vreg, "regulator is not marked sleep selectable\n");
		return -EINVAL;
	}

	/* Allow min_uV == max_uV == 0 to represent a disable request. */
	if (min_uV != 0 || max_uV != 0) {
		/*
		 * Check if request voltage is outside of allowed range. The
		 * regulator core has already checked that constraint range
		 * is inside of the physically allowed range.
		 */
		lim_min_uV = vreg->pdata.init_data.constraints.min_uV;
		lim_max_uV = vreg->pdata.init_data.constraints.max_uV;

		if (uV < lim_min_uV && max_uV >= lim_min_uV)
			uV = lim_min_uV;

		if (uV < lim_min_uV || uV > lim_max_uV) {
			vreg_err(vreg, "request v=[%d, %d] is outside allowed "
				"v=[%d, %d]\n", min_uV, max_uV, lim_min_uV,
				lim_max_uV);
			return -EINVAL;
		}

		/* Find the range which uV is inside of. */
		for (i = vreg->set_points->count - 1; i > 0; i--) {
			if (uV > vreg->set_points->range[i - 1].max_uV) {
				range = &vreg->set_points->range[i];
				break;
			}
		}

		/*
		 * Force uV to be an allowed set point and apply a ceiling
		 * function to non-set point values.
		 */
		uV = (uV - range->min_uV + range->step_uV - 1) / range->step_uV;
		uV = uV * range->step_uV + range->min_uV;

		if (uV > max_uV) {
			vreg_err(vreg,
			  "request v=[%d, %d] cannot be met by any set point; "
			  "next set point: %d\n",
			  min_uV, max_uV, uV);
			return -EINVAL;
		}
	}

	if (vreg->part->uV.mask) {
		val[vreg->part->uV.word] = uV << vreg->part->uV.shift;
		mask[vreg->part->uV.word] = vreg->part->uV.mask;
	} else {
		val[vreg->part->mV.word]
			= MICRO_TO_MILLI(uV) << vreg->part->mV.shift;
		mask[vreg->part->mV.word] = vreg->part->mV.mask;
	}

	rc = vreg_set_noirq(vreg, voter, sleep_also, mask[0], val[0], mask[1],
			    val[1], vreg->part->request_len, 1);
	if (rc)
		vreg_err(vreg, "vreg_set_noirq failed, rc=%d\n", rc);

	return rc;
}
static int __devinit
rpm_vreg_init_regulator(const struct rpm_regulator_init_data *pdata,
			struct device *dev)
{
	struct regulator_desc *rdesc = NULL;
	struct regulator_dev *rdev;
	struct vreg *vreg;
	unsigned pin_ctrl;
	int id, pin_fn;
	int rc = 0;

	if (!pdata) {
		pr_err("platform data missing\n");
		return -EINVAL;
	}

	id = pdata->id;

	if (id < config->vreg_id_min || id > config->vreg_id_max) {
		pr_err("invalid regulator id: %d\n", id);
		return -ENODEV;
	}

	if (!config->is_real_id(pdata->id))
		id = config->pc_id_to_real_id(pdata->id);
	vreg = &config->vregs[id];

	if (config->is_real_id(pdata->id))
		rdesc = &vreg->rdesc;
	else
		rdesc = &vreg->rdesc_pc;

	if (vreg->type < 0 || vreg->type > RPM_REGULATOR_TYPE_MAX) {
		pr_err("%s: invalid regulator type: %d\n",
			vreg->rdesc.name, vreg->type);
		return -EINVAL;
	}

	mutex_lock(&vreg->pc_lock);

	if (vreg->set_points)
		rdesc->n_voltages = vreg->set_points->n_voltages;
	else
		rdesc->n_voltages = 0;

	rdesc->id    = pdata->id;
	rdesc->owner = THIS_MODULE;
	rdesc->type  = REGULATOR_VOLTAGE;

	if (config->is_real_id(pdata->id)) {
		/*
		 * Real regulator; do not modify pin control and pin function
		 * values.
		 */
		rdesc->ops = vreg_ops[vreg->type];
		pin_ctrl = vreg->pdata.pin_ctrl;
		pin_fn = vreg->pdata.pin_fn;
		memcpy(&(vreg->pdata), pdata,
			sizeof(struct rpm_regulator_init_data));
		vreg->pdata.pin_ctrl = pin_ctrl;
		vreg->pdata.pin_fn = pin_fn;

		vreg->save_uV = vreg->pdata.default_uV;
		if (vreg->pdata.peak_uA >= vreg->hpm_min_load)
			vreg->mode = config->mode_hpm;
		else
			vreg->mode = config->mode_lpm;

		/* Initialize the RPM request. */
		SET_PART(vreg, ip,
		 MICRO_TO_MILLI(saturate_peak_load(vreg, vreg->pdata.peak_uA)));
		SET_PART(vreg, fm, vreg->pdata.force_mode);
		SET_PART(vreg, pm, vreg->pdata.power_mode);
		SET_PART(vreg, pd, vreg->pdata.pull_down_enable);
		SET_PART(vreg, ia,
		   MICRO_TO_MILLI(saturate_avg_load(vreg, vreg->pdata.avg_uA)));
		SET_PART(vreg, freq, vreg->pdata.freq);
		SET_PART(vreg, freq_clk_src, 0);
		SET_PART(vreg, comp_mode, 0);
		SET_PART(vreg, hpm, 0);
		if (!vreg->is_enabled_pc) {
			SET_PART(vreg, pf, config->pin_func_none);
			SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
		}
	} else {
		if ((pdata->pin_ctrl & RPM_VREG_PIN_CTRL_ALL)
		      == RPM_VREG_PIN_CTRL_NONE
		    && pdata->pin_fn != config->pin_func_sleep_b) {
			pr_err("%s: no pin control input specified\n",
				vreg->rdesc.name);
			mutex_unlock(&vreg->pc_lock);
			return -EINVAL;
		}
		rdesc->ops = &pin_control_ops;
		vreg->pdata.pin_ctrl = pdata->pin_ctrl;
		vreg->pdata.pin_fn = pdata->pin_fn;

		/* Initialize the RPM request. */
		pin_fn = config->pin_func_none;
		/* Allow pf=sleep_b to be specified by platform data. */
		if (vreg->pdata.pin_fn == config->pin_func_sleep_b)
			pin_fn = config->pin_func_sleep_b;
		SET_PART(vreg, pf, pin_fn);
		SET_PART(vreg, pc, RPM_VREG_PIN_CTRL_NONE);
	}

	mutex_unlock(&vreg->pc_lock);

	if (rc)
		goto bail;

	rdev = regulator_register(rdesc, dev, &(pdata->init_data), vreg);
	if (IS_ERR(rdev)) {
		rc = PTR_ERR(rdev);
		pr_err("regulator_register failed: %s, rc=%d\n",
			vreg->rdesc.name, rc);
		return rc;
	} else {
		if (config->is_real_id(pdata->id))
			vreg->rdev = rdev;
		else
			vreg->rdev_pc = rdev;
	}

bail:
	if (rc)
		pr_err("error for %s, rc=%d\n", vreg->rdesc.name, rc);

	return rc;
}