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); } }
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); }
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; }
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; }
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; }
/* * 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; }
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, ®); 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; }