示例#1
0
void program_mclk_shutdown(mic_ctx_t *mic_ctx, bool set)
{
	sbox_uos_pcu_ctrl_t uos_ctrl_regval;
	sbox_pcu_ctrl_t ctrl_regval;

	if(KNC_A_STEP == mic_ctx->bi_stepping) {
		ctrl_regval.value = pm_reg_read(mic_ctx,SBOX_PCU_CONTROL);
		ctrl_regval.bits.enable_mclk_pl_shutdown =  (set ? 1: 0);
		pm_reg_write(ctrl_regval.value, mic_ctx, SBOX_PCU_CONTROL);
	} else {
		uos_ctrl_regval.value = pm_reg_read(mic_ctx,
				SBOX_UOS_PCUCONTROL);
		uos_ctrl_regval.bits.enable_mclk_pll_shutdown = (set ? 1: 0);
		pm_reg_write(uos_ctrl_regval.value,
				mic_ctx, SBOX_UOS_PCUCONTROL);
	}
}
示例#2
0
void program_prevent_C3Exit(mic_ctx_t *mic_ctx, bool set)
{
	sbox_pcu_ctrl_t ctrl_regval;
	ctrl_regval.value = pm_reg_read(mic_ctx,SBOX_PCU_CONTROL);
	ctrl_regval.bits.prevent_auto_c3_exit = (set ? 1: 0);
	pm_reg_write(ctrl_regval.value, mic_ctx, SBOX_PCU_CONTROL);

}
示例#3
0
int set_host_state(mic_ctx_t *mic_ctx, PM_IDLE_STATE state) {

	int err = 0;
	sbox_host_pm_state_t hpmstate_regval = {0};
	hpmstate_regval.value = pm_reg_read(mic_ctx, SBOX_HOST_PMSTATE);
	hpmstate_regval.bits.host_pm_state = 0;
	hpmstate_regval.bits.host_pm_state = state;
	pm_reg_write(hpmstate_regval.value, mic_ctx, SBOX_HOST_PMSTATE);
	return err;
}
示例#4
0
void restore_pc6_registers(mic_ctx_t *mic_ctx, bool from_dpc3) {
	sbox_pcu_ctrl_t ctrl_regval = {0};
	sbox_uos_pcu_ctrl_t uos_ctrl_regval = {0};
	gbox_pm_control pmctrl_reg = {0};
	sbox_core_freq_t core_freq_reg = {0};

	if (!from_dpc3) {
		if(KNC_A_STEP == mic_ctx->bi_stepping) {
			ctrl_regval.value = pm_reg_read(mic_ctx, SBOX_PCU_CONTROL);
			ctrl_regval.bits.enable_mclk_pl_shutdown = 0;
			pm_reg_write(ctrl_regval.value, mic_ctx, SBOX_PCU_CONTROL);
		} else {
			uos_ctrl_regval.value = pm_reg_read(mic_ctx,SBOX_UOS_PCUCONTROL);
			uos_ctrl_regval.bits.enable_mclk_pll_shutdown = 0;
			pm_reg_write(uos_ctrl_regval.value, mic_ctx, SBOX_UOS_PCUCONTROL);
		}


		ctrl_regval.value = pm_reg_read(mic_ctx, SBOX_PCU_CONTROL);
		ctrl_regval.bits.prevent_auto_c3_exit = 0;
		pm_reg_write(ctrl_regval.value, mic_ctx, SBOX_PCU_CONTROL);
	}

	pmctrl_reg.value = pm_reg_read(mic_ctx, GBOX_PM_CTRL);
	pmctrl_reg.bits.in_pckgc6 = 0;
	pm_reg_write(pmctrl_reg.value, mic_ctx, GBOX_PM_CTRL);

	ctrl_regval.value = pm_reg_read(mic_ctx, SBOX_PCU_CONTROL);
	ctrl_regval.bits.grpB_pwrgood_mask = 0;
	pm_reg_write(ctrl_regval.value, mic_ctx, SBOX_PCU_CONTROL);

	core_freq_reg.value = pm_reg_read(mic_ctx, SBOX_COREFREQ);
	core_freq_reg.bits.booted = 1;
	pm_reg_write(core_freq_reg.value, mic_ctx, SBOX_COREFREQ);
}
static ssize_t pm8941_set_mask_enable(struct device *ldev,
	struct device_attribute *attr, const char *buf, size_t size)
{
	struct pm8941_flash_data *data = dev_get_drvdata(ldev);
	unsigned long mask;
	int rc = 0;

	if (kstrtoul(buf, 10, &mask))
		return -EINVAL;

	mutex_lock(&data->lock);
	rc = pm_reg_write(data, MASK_ENABLE, mask);
	if (rc)
		pm8941_dev_err(data, "mask_enable write failed(%d)\n", rc);
	mutex_unlock(&data->lock);

	return rc ? rc : size;
}
static ssize_t pm8941_set_vph_pwr_droop(struct device *ldev,
	struct device_attribute *attr, const char *buf, size_t size)
{
	struct pm8941_flash_data *data = dev_get_drvdata(ldev);
	unsigned long vph_pwr;
	int rc = 0;

	if (kstrtoul(buf, 10, &vph_pwr))
		return -EINVAL;

	mutex_lock(&data->lock);
	rc = pm_reg_write(data, VPH_PWR_DROOP, (u8)vph_pwr);
	if (rc)
		pm8941_dev_err(data, "vph pwr droop write failed(%d)\n", rc);
	mutex_unlock(&data->lock);

	return rc ? rc : size;
}
static ssize_t pm8941_set_fine_current_common(struct device *ldev, u16 offset,
	struct device_attribute *attr, const char *buf, size_t size)
{
	struct pm8941_flash_data *data = dev_get_drvdata(ldev);
	unsigned long fine_current;
	int rc = 0;

	if (kstrtoul(buf, 10, &fine_current))
		return -EINVAL;

	mutex_lock(&data->lock);
	if (fine_current > FLASH_MAX_FINE_LEVEL)
		fine_current = FLASH_MAX_FINE_LEVEL;

	rc = pm_reg_write(data, offset, (u8)fine_current);
	if (rc)
		pm8941_dev_err(data, "Fine current reg write failed(%d)\n", rc);
	mutex_unlock(&data->lock);

	return rc ? rc : size;
}
static ssize_t pm8941_set_startup_delay(struct device *ldev,
	struct device_attribute *attr, const char *buf, size_t size)
{
	struct pm8941_flash_data *data = dev_get_drvdata(ldev);
	unsigned long delay;
	int rc = 0;

	if (kstrtoul(buf, 10, &delay))
		return -EINVAL;

	mutex_lock(&data->lock);
	if (delay > DELAY_128us)
		delay = DELAY_128us;

	rc = pm_reg_write(data, STARTUP_DELAY, delay);
	if (rc)
		pm8941_dev_err(data, "Startup delay write failed(%d)\n", rc);
	mutex_unlock(&data->lock);

	return rc ? rc : size;
}
static void flash_turn_off_delayed(struct work_struct *work)
{
	struct delayed_work *dwork = to_delayed_work(work);
	struct pm8941_flash_data *data
		= container_of(dwork, struct pm8941_flash_data, dwork);
	int rc = 0;

	mutex_lock(&data->lock);
	data->scheduled = false;
	rc = rc ? rc :
		pm_reg_masked_write(data, STROBE_CONTROL,
		ENABLE_CURRENT_OUT, DISABLE_CURRENT_OUT);
	rc = rc ? rc :
		pm_reg_write(data, ENABLE_CONTROL,
		MODULE_DISABLE | CURR_MAX_200mA);
	rc = rc ? rc :
		pm8941_regulator_disable(&data->spmi_dev->dev,
		&data->boost_for_flash);
	if (rc)
		pm8941_dev_err(data, "reg write failed(%d)\n", rc);
	mutex_unlock(&data->lock);
}
static ssize_t pm8941_set_flash_timer(struct device *ldev,
	struct device_attribute *attr, const char *buf, size_t size)
{
	struct pm8941_flash_data *data = dev_get_drvdata(ldev);
	unsigned long duration;
	int rc = 0;

	if (kstrtoul(buf, 10, &duration))
		return -EINVAL;

	mutex_lock(&data->lock);
	if (duration > FLASH_DURATION_1280ms)
		duration = FLASH_DURATION_1280ms;

	data->turn_off_delay_ms = 10 * (duration + 1);
	rc = pm_reg_write(data, SAFETY_TIMER, (u8)duration);
	if (rc)
		pm8941_dev_err(data, "Safety timer reg write failed(%d)\n", rc);
	mutex_unlock(&data->lock);

	return rc ? rc : size;
}
示例#11
0
void set_vid(mic_ctx_t *mic_ctx, sbox_svid_control svidctrl_regval, unsigned int vidcode) {

	uint32_t temp;
	uint32_t svid_cmd = 0;
	uint32_t svid_dout = 0;
	temp = svid_cmd_fmt((KNC_SVID_ADDR << 13) |
			(KNC_SETVID_SLOW << 8) | vidcode);
	svid_cmd = (KNC_SVID_ADDR << 5) | KNC_SETVID_SLOW;
	svidctrl_regval.bits.svid_cmd = 0x0e0;
	svidctrl_regval.bits.svid_cmd = svid_cmd;

	svid_dout = temp & 0x1ff;
	svidctrl_regval.bits.svid_dout = 0;
	svidctrl_regval.bits.svid_dout = svid_dout;

	svidctrl_regval.bits.cmd_start = 0x1;
	pm_reg_write(svidctrl_regval.value, mic_ctx,
			SBOX_SVID_CONTROL);

	msleep(10);

	return;
}
示例#12
0
/*
 * pm_pc6_exit:
 *
 * Execute pc6 exit for a node.
 * mic_ctx: The driver context of the node.
 */
int pm_pc6_exit(mic_ctx_t *mic_ctx)
{

	int err = 0;

	sbox_host_pm_state_t hpmstate_regval;
	sbox_pcu_ctrl_t ctrl_regval;
	uint8_t tdp_vid = 0;
	uint8_t is_pll_locked;
	uint32_t wait_cnt;
	int i;


	if (!check_host_state(mic_ctx, PM_IDLE_STATE_PC6)) {
		PM_DEBUG("Wrong Host PM state. State = %d\n",
				 get_host_state(mic_ctx));
		err = -EINVAL;
		goto restore_registers;
	}

	hpmstate_regval.value = pm_reg_read(mic_ctx, SBOX_HOST_PMSTATE);
	tdp_vid = hpmstate_regval.bits.tdp_vid;
	PM_DEBUG("TDP_VID value obtained from Host PM Register = %d",tdp_vid);

	PM_DEBUG("Setting voltage to %dV using SVID Control\n",tdp_vid);
	err = set_vid_knc(mic_ctx, tdp_vid);
	if (err != 0) {
		printk(KERN_ERR "%s Failed PC6 entry...error in setting VID\n", 
				__func__);
		goto restore_registers;
	}

	ctrl_regval.value = pm_reg_read(mic_ctx, SBOX_PCU_CONTROL);

	program_mclk_shutdown(mic_ctx, false);
	program_prevent_C3Exit(mic_ctx, false);

	for(wait_cnt = 0; wait_cnt < 200; wait_cnt++) {
		ctrl_regval.value = pm_reg_read(mic_ctx,SBOX_PCU_CONTROL);
		is_pll_locked = ctrl_regval.bits.mclk_pll_lock;
		if(likely(is_pll_locked))
				break;
		msleep(10);
	}

	if(wait_cnt >= 200) {
		PM_DEBUG("mclk_pll_locked bit is not set.\n");
		err = -EAGAIN;
		goto restore_registers;
	}

	ctrl_regval.bits.grpB_pwrgood_mask = 0;
	pm_reg_write(ctrl_regval.value, mic_ctx, SBOX_PCU_CONTROL);

	if (!hw_active(mic_ctx)) {
		PM_DEBUG("Timing out waiting for hw to become active");
		goto restore_registers;
	}

	for(wait_cnt = 0; wait_cnt < 200; wait_cnt++) {
		if ((get_card_state(mic_ctx)) == PM_IDLE_STATE_PC0)
			break;
		msleep(10);
	}

	if(wait_cnt >= 200) {
		PM_DEBUG("PC6 Exit not complete.\n");
		err = -EFAULT;
		goto restore_registers;
	}

	mic_ctx->micpm_ctx.idle_state = PM_IDLE_STATE_PC0;

	for (i = 0; i <= mic_data.dd_numdevs; i++) {
		if (micscif_get_nodedep(mic_get_scifnode_id(mic_ctx), i) ==
				DEP_STATE_DISCONNECTED) {
			micscif_set_nodedep(mic_get_scifnode_id(mic_ctx), i,
					DEP_STATE_DEPENDENT);
		}
	}

	PM_PRINT("Node %d exited PC6\n",
			mic_get_scifnode_id(mic_ctx));
	goto exit;

restore_registers:
	restore_pc6_registers(mic_ctx, false);
exit:
	atomic_set(&mic_ctx->gate_interrupt, 0);
	tasklet_schedule(&mic_ctx->bi_dpc);
	return err;
}
示例#13
0
int pm_pc3_to_pc6_entry(mic_ctx_t *mic_ctx)
{
	int err;
	sbox_pcu_ctrl_t ctrl_regval;
	gbox_pm_control pmctrl_reg;
	sbox_core_freq_t core_freq_reg;

	if ((get_card_state(mic_ctx)) != PM_IDLE_STATE_PC3) {
		PM_DEBUG("Card not ready to go to PC6. \n");
		err = -EAGAIN;
		goto exit;
	}

	if (atomic_cmpxchg(&mic_ctx->gate_interrupt, 0, 1) == 1) {
		PM_DEBUG("Cannot gate interrupt handler while it is in use\n");
		err = -EFAULT;
		goto exit;
	}

	program_prevent_C3Exit(mic_ctx, true);
	program_mclk_shutdown(mic_ctx, true);

	/* Wait for uos to become idle. */
	if (!hw_idle(mic_ctx)) {
		program_mclk_shutdown(mic_ctx, false);
		if (!hw_idle(mic_ctx)) {
			program_prevent_C3Exit(mic_ctx, false);
			PM_DEBUG("Card not ready to go to PC6. \n");
			err = -EAGAIN;
			goto intr_ungate;
		} else {
			program_mclk_shutdown(mic_ctx, true);
		}
	}

	pmctrl_reg.value = pm_reg_read(mic_ctx, GBOX_PM_CTRL);
	pmctrl_reg.bits.in_pckgc6 = 1;
	pm_reg_write(pmctrl_reg.value, mic_ctx, GBOX_PM_CTRL);

	core_freq_reg.value = pm_reg_read(mic_ctx, SBOX_COREFREQ);
	core_freq_reg.bits.booted = 0;
	pm_reg_write(core_freq_reg.value, mic_ctx, SBOX_COREFREQ);

	udelay(500);

	ctrl_regval.value = pm_reg_read(mic_ctx, SBOX_PCU_CONTROL);
	ctrl_regval.bits.grpB_pwrgood_mask = 1;
	pm_reg_write(ctrl_regval.value, mic_ctx, SBOX_PCU_CONTROL);

	err = set_vid_knc(mic_ctx, 0);
	if (err != 0) {
		PM_DEBUG("Aborting PC6 entry...Failed to set VID\n");
		restore_pc6_registers(mic_ctx, true);
		goto intr_ungate;
	}

	mic_ctx->micpm_ctx.idle_state = PM_IDLE_STATE_PC6;
	set_host_state(mic_ctx, PM_IDLE_STATE_PC6);

	dma_prep_suspend(mic_ctx->dma_handle);

	PM_PRINT("Node %d entered PC6\n",
		mic_get_scifnode_id(mic_ctx));

	return err;

intr_ungate:
	atomic_set(&mic_ctx->gate_interrupt, 0);
	tasklet_schedule(&mic_ctx->bi_dpc);
exit:
	return err;
}
static int __devinit pm8941_flash_initialize(struct pm8941_flash_data *data)
{
	int rc;
	u8 reg;

	/* Set strobe */
	reg = DISABLE_CURRENT_OUT | data->flash_cfg.hw_strobe_config;
	rc = pm_reg_write(data, STROBE_CONTROL, reg);
	if (rc) {
		pm8941_dev_err(data, "Strobe write failed(%d)\n", rc);
		return rc;
	}

	/* Safety timer */
	rc = pm_reg_read(data, SAFETY_TIMER, &reg);
	if (rc) {
		pm8941_dev_err(data, "Safety timer read failed(%d)\n", rc);
		return rc;
	}
	data->turn_off_delay_ms = ++reg * 10;

	/* Set clamp current */
	rc = pm_reg_write(data, CLAMP_CURRENT, data->flash_cfg.clamp_curr);
	if (rc) {
		pm8941_dev_err(data, "Clamp reg write failed(%d)\n", rc);
		return rc;
	}

	/* Set headroom */
	rc = pm_reg_write(data, HEADROOM, data->flash_cfg.headroom);
	if (rc) {
		pm8941_dev_err(data, "Headroom reg write failed(%d)\n", rc);
		return rc;
	}

	/* Set mask enable */
	rc = pm_reg_write(data, MASK_ENABLE, data->flash_cfg.mask_enable << 5);
	if (rc) {
		pm8941_dev_err(data, "Mask enable reg write failed(%d)\n", rc);
		return rc;
	}

	/* Set startup delay */
	rc = pm_reg_write(data, STARTUP_DELAY, data->flash_cfg.startup_dly);
	if (rc) {
		pm8941_dev_err(data, "Start delay reg write failed(%d)\n", rc);
		return rc;
	}

	/* Set VPH_PWR_DROOP */
	reg = data->flash_cfg.vph_pwr_droop.enable << 7
		| data->flash_cfg.vph_pwr_droop.threshold << 4
		| data->flash_cfg.vph_pwr_droop.debounce_time;
	rc = pm_reg_write(data, VPH_PWR_DROOP, reg);
	if (rc) {
		pm8941_dev_err(data, "Start delay reg write failed(%d)\n", rc);
		return rc;
	}

	/* Set current */
	rc = rc ? rc : pm_reg_write(data, LED1_CURRENT, 0xA);
	if (rc) {
		pm8941_dev_err(data, "current1 reg write failed(%d)\n", rc);
		return rc;
	}
	rc = rc ? rc : pm_reg_write(data, LED2_CURRENT, 0xA);
	if (rc) {
		pm8941_dev_err(data, "current2 reg write failed(%d)\n", rc);
		return rc;
	}
	/* Set enable module */
	rc = pm_reg_write(data, ENABLE_CONTROL,
		MODULE_DISABLE | CURR_MAX_200mA);
	if (rc) {
		pm8941_dev_err(data, "Enable module failed(%d)\n", rc);
		return rc;
	}

	/* Disable watchdog timer */
	rc = rc ? rc : pm_reg_write(data, SEC_ACCESS, ENABLE_SEC_ACCESS);
	rc = rc ? rc : pm_reg_write(data, TEST3_TIMER,
		TEST3_ENABLE_FLASH_TIMER | TEST3_DISABLE_WATCHDOG_TIMER);
	rc = rc ? rc : pm_reg_write(data, SEC_ACCESS, DISABLE_SEC_ACCESS);
	if (rc) {
		pm8941_dev_err(data, "Disable watchdog failed(%d)\n", rc);
		return rc;
	}

	return 0;
}
static ssize_t pm8941_set_mode(struct device *ldev,
	struct device_attribute *attr, const char *buf, size_t size)
{
	struct pm8941_flash_data *data = dev_get_drvdata(ldev);
	unsigned long mode;
	int rc = 0;

	if (kstrtoul(buf, 10, &mode))
		return -EINVAL;

	if (mode >= FLASH_MODE_MAX)
		return -EINVAL;

	mutex_lock(&data->lock);

	if (data->scheduled) {
		mutex_unlock(&data->lock);
		flush_delayed_work_sync(&data->dwork);
		mutex_lock(&data->lock);
	} else {
		rc = pm_reg_masked_write(data, STROBE_CONTROL,
			ENABLE_CURRENT_OUT, DISABLE_CURRENT_OUT);
		if (rc)
			goto error;

		rc = pm_reg_write(data, ENABLE_CONTROL,
			MODULE_DISABLE | CURR_MAX_200mA);
		if (rc)
			goto error;

		rc = pm8941_regulator_disable(&data->spmi_dev->dev,
			&data->boost_for_torch);
		rc = rc ? rc :
			pm8941_regulator_disable(&data->spmi_dev->dev,
			&data->boost_for_flash);
		if (rc)
			goto exit;
	}

	switch (mode) {
	case FLASH_MODE_FLASH:
		rc = rc ? rc :
			pm8941_regulator_enable(&data->spmi_dev->dev,
				&data->boost_for_flash);
		rc = rc ? rc :
			pm_reg_write(data, TMR_CONTROL, ENABLE_FLASH_TIMER);
		rc = rc ? rc :
			pm_reg_write(data, VREG_OK_FORCE, 0x40);
		rc = rc ? rc :
			pm_reg_write(data, FAULT_DETECT, ENABLE_SELF_CHECK);
		rc = rc ? rc :
			pm_reg_write(data, MAX_CURRENT, 0x4F);
		rc = rc ? rc :
			pm_reg_write(data, ENABLE_CONTROL,
			MODULE_ENABLE | CURR_MAX_1A);
		rc = rc ? rc :
			pm_reg_masked_write(data, STROBE_CONTROL,
			ENABLE_CURRENT_OUT, ENABLE_CURRENT_OUT);

		if (!is_hw_strobe(data)) {
			data->scheduled = true;
			INIT_DELAYED_WORK(&data->dwork, flash_turn_off_delayed);
			schedule_delayed_work(&data->dwork,
				msecs_to_jiffies(data->turn_off_delay_ms));
		}
		break;
	case FLASH_MODE_TORCH:
		rc = rc ? rc :
			pm_reg_masked_write(data, STROBE_CONTROL,
				STROBE_SELECT_HW, STROBE_SELECT_SW);
		rc = rc ? rc :
			pm8941_regulator_enable(&data->spmi_dev->dev,
				&data->boost_for_torch);
		rc = rc ? rc :
			pm_reg_write(data, MAX_CURRENT, 0xF);
		rc = rc ? rc :
			pm_reg_write(data, TMR_CONTROL, ENABLE_WATCHDOG_TIMER);
		rc = rc ? rc :
			pm_reg_write(data, ENABLE_CONTROL,
			MODULE_ENABLE | CURR_MAX_200mA);
		rc = rc ? rc :
			pm_reg_masked_write(data, STROBE_CONTROL,
			ENABLE_CURRENT_OUT, ENABLE_CURRENT_OUT);
		break;
	case FLASH_MODE_NONE:
	default:
		break;
	}
error:
	if (rc)
		pm8941_dev_err(data, "reg write failed(%d)\n", rc);
exit:
	mutex_unlock(&data->lock);

	return rc ? rc : size;
}