static void charge_current_set(int cable_type) { static struct regulator *regulator; int ret; if (regulator == NULL) { regulator = regulator_get(NULL, "vinchg1"); if (IS_ERR_OR_NULL(regulator)) { pr_err("%s : falied to get regulator\n", __func__); regulator = NULL; goto out; } } switch (cable_type) { case CABLE_TYPE_USB: ret = regulator_set_current_limit(regulator, CURRENT_USB, CURRENT_USB + 25000); break; case CABLE_TYPE_TA: ret = regulator_set_current_limit(regulator, CURRENT_TA, CURRENT_TA + 25000); break; default: pr_err("%s : unsupported type of cable\n", __func__); } if (ret < 0) pr_err("%s : failed to set current limit\n", __func__); out: return; }
/* interface to regulator framework */ static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA) { struct regulator *vbus_draw = nop->vbus_draw; int enabled; int ret; if (!vbus_draw) return; enabled = nop->vbus_draw_enabled; if (mA) { regulator_set_current_limit(vbus_draw, 0, 1000 * mA); if (!enabled) { ret = regulator_enable(vbus_draw); if (ret < 0) return; nop->vbus_draw_enabled = 1; } } else { if (enabled) { ret = regulator_disable(vbus_draw); if (ret < 0) return; nop->vbus_draw_enabled = 0; } } nop->mA = mA; }
/* interface to regulator framework */ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA) { struct regulator *vbus_draw = gpio_vbus->vbus_draw; int enabled; int ret; if (!vbus_draw) return; enabled = gpio_vbus->vbus_draw_enabled; if (mA) { regulator_set_current_limit(vbus_draw, 0, 1000 * mA); if (!enabled) { ret = regulator_enable(vbus_draw); if (ret < 0) return; gpio_vbus->vbus_draw_enabled = 1; } } else { if (enabled) { ret = regulator_disable(vbus_draw); if (ret < 0) return; gpio_vbus->vbus_draw_enabled = 0; } } gpio_vbus->mA = mA; }
static void led_work(struct work_struct *work) { struct wm8350_led *led = container_of(work, struct wm8350_led, work); int ret; int uA; unsigned long flags; mutex_lock(&led->mutex); spin_lock_irqsave(&led->value_lock, flags); if (led->value == LED_OFF) { spin_unlock_irqrestore(&led->value_lock, flags); wm8350_led_disable(led); goto out; } uA = (led->max_uA_index * led->value) / LED_FULL; spin_unlock_irqrestore(&led->value_lock, flags); BUG_ON(uA >= ARRAY_SIZE(isink_cur)); ret = regulator_set_current_limit(led->isink, isink_cur[uA], isink_cur[uA]); if (ret != 0) dev_err(led->cdev.dev, "Failed to set %duA: %d\n", isink_cur[uA], ret); wm8350_led_enable(led); out: mutex_unlock(&led->mutex); }
static void update_current_limit_constraints(struct virtual_consumer_data *data) { int ret; if (data->max_uA && data->min_uA <= data->max_uA) { ret = regulator_set_current_limit(data->regulator, data->min_uA, data->max_uA); if (ret != 0) { pr_err("regulator_set_current_limit() failed: %d\n", ret); return; } } if (data->max_uA && !data->enabled) { ret = regulator_enable(data->regulator); if (ret == 0) data->enabled = 1; else printk(KERN_ERR "regulator_enable() failed: %d\n", ret); } if (!(data->min_uA && data->max_uA) && data->enabled) { ret = regulator_disable(data->regulator); if (ret == 0) data->enabled = 0; else printk(KERN_ERR "regulator_disable() failed: %d\n", ret); } }
static int max77665_charger_types(struct max77665_charger *charger) { #define MA_TO_UA 1000 enum cable_status_t cable_status = charger->cable_status; int chgin_ilim = 0; int ret; switch (cable_status) { case CABLE_TYPE_USB: //USB input current 500mA chgin_ilim = charger->chgin_ilim_usb *MA_TO_UA; break; case CABLE_TYPE_AC: //AC input current 1200mA chgin_ilim = charger->chgin_ilim_ac * MA_TO_UA; break; default: chgin_ilim = 0; break; } if (chgin_ilim) { /* set ilim cur */ ret = regulator_set_current_limit(charger->ps, chgin_ilim, MAX_AC_CURRENT*MA_TO_UA); if (ret) { pr_err("failed to set current limit\n"); return ret; } } if(delayed_work_pending(&charger->poll_dwork)) cancel_delayed_work(&charger->poll_dwork); schedule_delayed_work_on(0, &charger->poll_dwork, 0); return 0; }
static void update_charger(void) { static int regulator_enabled; int max_uA = pdata->ac_max_uA; if (pdata->set_charge) { if (new_ac_status > 0) { dev_dbg(dev, "charger on (AC)\n"); pdata->set_charge(PDA_POWER_CHARGE_AC); } else if (new_usb_status > 0) { dev_dbg(dev, "charger on (USB)\n"); pdata->set_charge(PDA_POWER_CHARGE_USB); } else { dev_dbg(dev, "charger off\n"); pdata->set_charge(0); } } else if (ac_draw) { if (new_ac_status > 0) { regulator_set_current_limit(ac_draw, max_uA, max_uA); if (!regulator_enabled) { dev_dbg(dev, "charger on (AC)\n"); regulator_enable(ac_draw); regulator_enabled = 1; } } else { if (regulator_enabled) { dev_dbg(dev, "charger off\n"); regulator_disable(ac_draw); regulator_enabled = 0; } } } }
static void regulator_led_set_value(struct regulator_led *led) { int voltage; int ret; struct regulator *movie; mutex_lock(&led->mutex); if(led->cdev.flags & LED_SUSPENDED) goto out; if (led->value == LED_OFF) { regulator_led_disable(led); goto out; } movie = regulator_get(NULL, "led_movie"); if(IS_ERR(movie)) { pr_err("%s: led_movie is failed.\n", __func__); goto out; } if (regulator_is_enabled(movie) > 0) { pr_info("%s: led_movie is enabled.\n", __func__); goto end; } #if 0 //TODO if (led->cdev.max_brightness > 1) { voltage = led_regulator_get_voltage(led->vcc, led->value); dev_dbg(led->cdev.dev, "brightness: %d voltage: %d\n", led->value, voltage); ret = regulator_set_voltage(led->vcc, voltage, voltage); if (ret != 0) dev_err(led->cdev.dev, "Failed to set voltage %d: %d\n", voltage, ret); } #endif regulator_set_current_limit(led->vcc, 90000, 110000); regulator_led_enable(led); end: regulator_put(movie); out: mutex_unlock(&led->mutex); }
static int bc_sm_restart(struct stmp3xxx_info *info) { ddi_bc_Status_t bcret; int ret = 0; mutex_lock(&info->sm_lock); /* ungate power clk */ ddi_power_SetPowerClkGate(0); /* * config battery charger state machine and move it to the Disabled * state. This must be done before starting the state machine. */ bcret = ddi_bc_Init(info->sm_cfg); if (bcret != DDI_BC_STATUS_SUCCESS) { dev_err(info->dev, "battery charger init failed: %d\n", bcret); ret = -EIO; goto out; } else { if (!info->regulator) { info->regulator = regulator_get(NULL, "charger-1"); if (!info->regulator || IS_ERR(info->regulator)) { dev_err(info->dev, "%s: failed to get regulator\n", __func__); info->regulator = NULL; } else { regulator_set_current_limit( info->regulator, 0, 0); regulator_set_mode(info->regulator, REGULATOR_MODE_FAST); } } } /* schedule first call to state machine */ mod_timer(&info->sm_timer, jiffies + 1); out: mutex_unlock(&info->sm_lock); return ret; }
static ssize_t pt_val_set(struct device *d, struct device_attribute *attr, const char *buf, size_t size) { int i, ret; REG_GET(); ret = sscanf(buf, "%u", &i); if (ret != 1) return -EINVAL; mutex_lock(&run_mutex); if (!regulator_set_current_limit(reg, i, i)) { mod_timer(&pt_timer, jiffies + msecs_to_jiffies(timer_delay)); return size; } else { mutex_unlock(&run_mutex); return -EPERM; } }
static void update_current_limit_constraints(struct device *dev, struct virtual_consumer_data *data) { int ret; if (data->max_uA && data->min_uA <= data->max_uA) { dev_dbg(dev, "Requesting %d-%duA\n", data->min_uA, data->max_uA); ret = regulator_set_current_limit(data->regulator, data->min_uA, data->max_uA); if (ret != 0) { dev_err(dev, "regulator_set_current_limit() failed: %d\n", ret); return; } } if (data->max_uA && !data->enabled) { dev_dbg(dev, "Enabling regulator\n"); ret = regulator_enable(data->regulator); if (ret == 0) data->enabled = true; else dev_err(dev, "regulator_enable() failed: %d\n", ret); } if (!(data->min_uA && data->max_uA) && data->enabled) { dev_dbg(dev, "Disabling regulator\n"); ret = regulator_disable(data->regulator); if (ret == 0) data->enabled = false; else dev_err(dev, "regulator_disable() failed: %d\n", ret); } }
static ssize_t pt_val_fset(struct device *d, struct device_attribute *attr, const char *buf, size_t size) { int i, ret; ret = sscanf(buf, "%u", &i); if (ret != 1) return -EINVAL; if (!freg) { freg = regulator_get(NULL, "stmp3xxx-bl-1"); if (!freg || IS_ERR(freg)) { freg = NULL ; return -ENODEV; } } regulator_set_mode(freg, REGULATOR_MODE_NORMAL); if (!regulator_set_current_limit(freg, i, i)) printk(KERN_ERR "got backlight reg\n"); else printk(KERN_ERR "failed to get backlight reg"); return size; }
static int set_bl_intensity(struct mxs_platform_bl_data *data, struct backlight_device *bd, int suspended) { int intensity = bd->props.brightness; int scaled_int; if (bd->props.power != FB_BLANK_UNBLANK) intensity = 0; if (bd->props.fb_blank != FB_BLANK_UNBLANK) intensity = 0; if (suspended) intensity = 0; /* * This is not too cool but what can we do? * Luminance changes non-linearly... */ if (regulator_set_current_limit (data->regulator, bl_to_power(intensity), bl_to_power(intensity))) return -EBUSY; scaled_int = values[intensity / 10]; if (scaled_int < 100) { int rem = intensity - 10 * (intensity / 10); /* r = i % 10; */ scaled_int += rem * (values[intensity / 10 + 1] - values[intensity / 10]) / 10; } __raw_writel(BF_PWM_ACTIVEn_INACTIVE(scaled_int) | BF_PWM_ACTIVEn_ACTIVE(0), REGS_PWM_BASE + HW_PWM_ACTIVEn(2)); __raw_writel(BF_PWM_PERIODn_CDIV(6) | /* divide by 64 */ BF_PWM_PERIODn_INACTIVE_STATE(2) | /* low */ BF_PWM_PERIODn_ACTIVE_STATE(3) | /* high */ BF_PWM_PERIODn_PERIOD(399), REGS_PWM_BASE + HW_PWM_PERIODn(2)); return 0; }
static void led_work(struct work_struct *work) { struct wm8350_led *led = container_of(work, struct wm8350_led, work); int ret; int uA; unsigned long flags; mutex_lock(&led->mutex); spin_lock_irqsave(&led->value_lock, flags); if (led->value == LED_OFF) { spin_unlock_irqrestore(&led->value_lock, flags); wm8350_led_disable(led); goto out; } /* This scales linearly into the index of valid current * settings which results in a linear scaling of perceived * brightness due to the non-linear current settings provided * by the hardware. */ uA = (led->max_uA_index * led->value) / LED_FULL; spin_unlock_irqrestore(&led->value_lock, flags); BUG_ON(uA >= ARRAY_SIZE(isink_cur)); ret = regulator_set_current_limit(led->isink, isink_cur[uA], isink_cur[uA]); if (ret != 0) dev_err(led->cdev.dev, "Failed to set %duA: %d\n", isink_cur[uA], ret); wm8350_led_enable(led); out: mutex_unlock(&led->mutex); }
int vcc_cmds_tx(struct platform_device *pdev, struct vcc_desc *cmds, int cnt) { int ret = 0; struct vcc_desc *cm = NULL; int i = 0; cm = cmds; for (i = 0; i < cnt; i++) { if ((cm == NULL) || (cm->id == NULL)) { balongfb_loge("cm or cm->id is null! index=%d\n", i); ret = -1; goto error; } if (cm->dtype == DTYPE_VCC_GET) { BUG_ON(pdev == NULL); *(cm->regulator) = regulator_get(&pdev->dev, cm->id); if (IS_ERR(*(cm->regulator))) { balongfb_loge("failed to get %s regulator!\n", cm->id); ret = -1; goto error; } } else if (cm->dtype == DTYPE_VCC_PUT) { if (!IS_ERR(*(cm->regulator))) { regulator_put(*(cm->regulator)); } } else if (cm->dtype == DTYPE_VCC_ENABLE) { if (!IS_ERR(*(cm->regulator))) { if (regulator_enable(*(cm->regulator)) != 0) { balongfb_loge("failed to enable %s regulator!\n", cm->id); ret = -1; goto error; } } } else if (cm->dtype == DTYPE_VCC_DISABLE) { if (!IS_ERR(*(cm->regulator))) { if (regulator_disable(*(cm->regulator)) != 0) { balongfb_loge("failed to disable %s regulator!\n", cm->id); ret = -1; goto error; } } } else if (cm->dtype == DTYPE_VCC_SET_VOLTAGE) { if (!IS_ERR(*(cm->regulator))) { if (regulator_set_voltage(*(cm->regulator), cm->min_uV, cm->max_uV) != 0) { balongfb_loge("failed to set %s regulator voltage!\n", cm->id); ret = -1; goto error; } } } else if (cm->dtype == DTYPE_VCC_SET_CURRENT) { if (!IS_ERR(*(cm->regulator))) { if (regulator_set_current_limit(*(cm->regulator), cm->min_uA, cm->max_uA) != 0) { balongfb_loge("failed to set %s regulator current!\n", cm->id); ret = -1; goto error; } } } else { balongfb_loge("dtype=%x NOT supported\n", cm->dtype); ret = -1; goto error; } if (cm->wait) { if (cm->waittype == WAIT_TYPE_US) udelay(cm->wait); else if (cm->waittype == WAIT_TYPE_MS) mdelay(cm->wait); else mdelay(cm->wait * 1000); } cm++; } return 0; error: return ret; }
static int hw_scharger_flash_mode(struct hw_flash_ctrl_t *flash_ctrl, int data) { struct hw_scharger_private_data_t *pdata; int ret = 0; cam_debug("%s data=%d.\n", __func__, data); if (NULL == flash_ctrl) { cam_err("%s flash_ctrl is NULL.", __func__); return -1; } pdata = (struct hw_scharger_private_data_t *)flash_ctrl->pdata; if (data >= pdata->flash_led_num) { cam_err("Unsupport flash_lum_level: %d", data); return -1; } if ((NULL == pdata->flash_inter_ldo) || (NULL == pdata->flash_mode_ldo)) { cam_err("%s regulator is NULL", __func__); return -1; } /*if flash has already on do nothing*/ if(BIT(FLASH_MODE) & pdata->status){ cam_info("%s already in flash mode, do nothing",__func__); return 0; } ret = scharger_flash_led_timeout_config(FLASH_TIMEOUT_MS); if (ret < 0) { cam_err("%s scharger_flash_led_timeout_config fail ret = %d ", __func__, ret); regulator_disable(pdata->flash_inter_ldo); return ret; } ret = scharger_flash_led_timeout_enable(); if (ret < 0) { cam_err("%s scharger_flash_led_timeout_enable fail ret = %d ", __func__, ret); return ret; } ret = regulator_enable(pdata->flash_inter_ldo); if (ret < 0) { cam_err("%s regulator_enable flash_inter_ldo fail ret = %d", __func__, ret); /* #if defined (CONFIG_HUAWEI_DSM) */ /* if (!dsm_client_ocuppy(client_ovisp22)){ */ /* dsm_client_record(client_ovisp22,"[%s]regulator_enable flash_inter_ldo fail mode %d\n",__func__,mode); */ /* dsm_client_notify(client_ovisp22, DSM_ISP22_FLASH_ERROR_NO); */ /* } */ /* #endif */ return ret; } udelay(500); ret = regulator_set_current_limit(pdata->flash_mode_ldo, pdata->flash_led[data], pdata->flash_led[data]); if (ret < 0) { cam_err("%s regulator_set_current_limit fail ret = %d current is %d", __func__, ret, (pdata->flash_led[data])); regulator_disable(pdata->flash_inter_ldo); return ret; } ret = regulator_enable(pdata->flash_mode_ldo); if (ret < 0) { cam_err("%s regulator_enable torch_mode_ldo fail ret = %d", __func__, ret); /* #if defined (CONFIG_HUAWEI_DSM) */ /* if (!dsm_client_ocuppy(client_ovisp22)){ */ /* dsm_client_record(client_ovisp22,"[%s]regulator_enable flash_mode_ldo fail mode %d\n",__func__,mode); */ /* dsm_client_notify(client_ovisp22, DSM_ISP22_FLASH_ERROR_NO); */ /* } */ /* #endif */ regulator_disable(pdata->flash_inter_ldo); return ret; } pdata->status |= BIT(FLASH_MODE); return 0; }
/* * Assumption: * AC power can't be switched to USB w/o system reboot * and vice-versa */ static void state_machine_work(struct work_struct *work) { struct stmp3xxx_info *info = container_of(work, struct stmp3xxx_info, sm_work); mutex_lock(&info->sm_lock); handle_battery_voltage_changes(info); check_and_handle_5v_connection(info); if ((info->sm_5v_connection_status != _5v_connected_verified) || !(info->regulator)) { mod_timer(&info->sm_timer, jiffies + msecs_to_jiffies(100)); goto out; } /* if we made it here, we have a verified 5v connection */ if (is_ac_online()) { if (info->is_ac_online) goto done; /* ac supply connected */ dev_info(info->dev, "changed power connection to ac/5v.\n)"); dev_info(info->dev, "5v current limit set to %u.\n", NON_USB_5V_SUPPLY_CURRENT_LIMIT_MA); info->is_ac_online = 1; info->is_usb_online = 0; ddi_power_set_4p2_ilimit( NON_USB_5V_SUPPLY_CURRENT_LIMIT_MA); ddi_bc_SetCurrentLimit( NON_USB_5V_SUPPLY_CURRENT_LIMIT_MA /*mA*/); if (regulator_set_current_limit(info->regulator, 0, NON_USB_5V_SUPPLY_CURRENT_LIMIT_MA*1000)) { dev_err(info->dev, "reg_set_current(%duA) failed\n", NON_USB_5V_SUPPLY_CURRENT_LIMIT_MA*1000); } ddi_bc_SetEnable(); goto done; } if (!is_usb_online()) goto out; if (info->is_usb_online & USB_REG_SET) goto done; info->is_ac_online = 0; info->is_usb_online |= USB_ONLINE; if (!(info->is_usb_online & USB_N_SEND)) { info->is_usb_online |= USB_N_SEND; } dev_dbg(info->dev, "%s: charge current set to %dmA\n", __func__, POWERED_USB_5V_CURRENT_LIMIT_MA); if (regulator_set_current_limit(info->regulator, 0, POWERED_USB_5V_CURRENT_LIMIT_MA*1000)) { dev_err(info->dev, "reg_set_current(%duA) failed\n", POWERED_USB_5V_CURRENT_LIMIT_MA*1000); } else { ddi_bc_SetCurrentLimit(POWERED_USB_5V_CURRENT_LIMIT_MA/*mA*/); ddi_bc_SetEnable(); } if (info->is_usb_online & USB_SM_RESTART) { info->is_usb_online &= ~USB_SM_RESTART; ddi_bc_SetEnable(); } info->is_usb_online |= USB_REG_SET; dev_info(info->dev, "changed power connection to usb/5v present\n"); done: ddi_bc_StateMachine(); out: mutex_unlock(&info->sm_lock); }
/* ************************************************************************** * FunctionName: scharger_flash_turn_on; * Description : turn on flashlight; * Input : NA; * Output : NA; * ReturnValue : NA; * Other : NA; ************************************************************************** */ static int scharger_flash_turn_on(work_mode mode, flash_lum_level lum) { int ret = 0; print_info("enter %s work_mode = %d , lum = %d",__func__, mode, lum); SAFE_DOWN(&switch_lock); if (mode == TORCH_MODE) { if (lum >= TORCH_LUM_LEVEL_NUM) { print_error("Unsupport torch_lum_level: %d", lum); ret = -1; goto out; } flash_mode = TORCH_MODE; /*if flash has already on go out do nothing*/ if(FLASH_TORCH_MODE&flash_on){ ret = 0; print_info("%s torch mode already in do nothing",__func__); goto out; } ret = regulator_set_current_limit(torch_mode_ldo, torch_lum_table[lum], torch_lum_table[lum]); if (ret < 0){ print_error("%s regulator_set_current_limit fail ret = %d current is %d", __func__, ret, (torch_lum_table[lum])); goto out; } ret = regulator_enable(flash_inter_ldo); if (ret < 0){ print_error("%s regulator_enable flash_inter_ldo fail ret = %d", __func__, ret); #if defined (CONFIG_HUAWEI_DSM) if (!dsm_client_ocuppy(client_ovisp22)){ dsm_client_record(client_ovisp22,"[%s]regulator_enable flash_inter_ldo fail mode %d\n",__func__,mode); dsm_client_notify(client_ovisp22, DSM_ISP22_FLASH_ERROR_NO); } #endif goto out; } udelay(500); ret = regulator_enable(torch_mode_ldo); if (ret < 0){ print_error("%s regulator_enable torch_mode_ldo fail ret = %d", __func__, ret); #if defined (CONFIG_HUAWEI_DSM) if (!dsm_client_ocuppy(client_ovisp22)){ dsm_client_record(client_ovisp22,"[%s]regulator_enable torch_mode_ldo fail mode %d\n",__func__,mode); dsm_client_notify(client_ovisp22, DSM_ISP22_FLASH_ERROR_NO); } #endif if (flash_inter_ldo){ regulator_disable(flash_inter_ldo); } goto out; } flash_on |= FLASH_TORCH_MODE; } else { if (lum >= FLASH_LUM_LEVEL_NUM) { print_error("Unsupport flash_lum_level: %d", lum); ret = -1; goto out; } flash_mode = FLASH_MODE; if(FLASH_FLASH_MODE&flash_on){ ret = 0; print_info("%s flash mode already in do nothing",__func__); goto out; } if(audio_codec_mute_flag){ audio_codec_mute_pga(1); flash_mute = true; } ret = regulator_set_current_limit(flash_mode_ldo, flash_lum_table[lum], flash_lum_table[lum]); if (ret < 0){ print_error("%s regulator_set_current_limit fail ret = %d current is %d", __func__, ret, (flash_lum_table[lum])); goto out; } ret = scharger_flash_led_timeout_config(FLASH_TIMEOUT_MS); if (ret < 0){ print_error("%s scharger_flash_led_timeout_config fail ret = %d ", __func__, ret); goto out; } ret = scharger_flash_led_timeout_enable(); if (ret < 0){ print_error("%s scharger_flash_led_timeout_enable fail ret = %d ", __func__, ret); goto out; } ret = regulator_enable(flash_inter_ldo); if (ret < 0){ print_error("%s regulator_enable flash_inter_ldo fail ret = %d", __func__, ret); #if defined (CONFIG_HUAWEI_DSM) if (!dsm_client_ocuppy(client_ovisp22)){ dsm_client_record(client_ovisp22,"[%s]regulator_enable flash_inter_ldo fail mode %d\n",__func__,mode); dsm_client_notify(client_ovisp22, DSM_ISP22_FLASH_ERROR_NO); } #endif goto out; } udelay(500); ret = regulator_enable(flash_mode_ldo); if (ret < 0){ print_error("%s regulator_enable torch_mode_ldo fail ret = %d", __func__, ret); #if defined (CONFIG_HUAWEI_DSM) if (!dsm_client_ocuppy(client_ovisp22)){ dsm_client_record(client_ovisp22,"[%s]regulator_enable flash_mode_ldo fail mode %d\n",__func__,mode); dsm_client_notify(client_ovisp22, DSM_ISP22_FLASH_ERROR_NO); } #endif if (flash_inter_ldo){ regulator_disable(flash_inter_ldo); } goto out; } flash_on |= FLASH_FLASH_MODE; } out: SAFE_UP(&switch_lock); return ret; }
static void timer_func(unsigned long data) { regulator_set_current_limit(reg, 0, 0); mutex_unlock(&run_mutex); }
static void check_and_handle_5v_connection(struct stmp3xxx_info *info) { switch (ddi_power_GetPmu5vStatus()) { case new_5v_connection: ddi_power_enable_5v_disconnect_detection(); info->sm_5v_connection_status = _5v_connected_unverified; case existing_5v_connection: if (info->sm_5v_connection_status != _5v_connected_verified) { /* we allow some time to pass before considering * the 5v connection to be ready to use. This * will give the USB system time to enumerate * (coordination with USB driver to be added * in the future). */ /* handle jiffies rollover case */ if ((jiffies - info->sm_new_5v_connection_jiffies) < 0) { info->sm_new_5v_connection_jiffies = jiffies; break; } if ((jiffies_to_msecs(jiffies - info->sm_new_5v_connection_jiffies)) > _5V_DEBOUNCE_TIME_MS) { info->sm_5v_connection_status = _5v_connected_verified; dev_info(info->dev, "5v connection verified\n"); ddi_power_Enable4p2(450); /* part of handling for errata. It is * now "somewhat" safe to * turn on vddio interrupts again */ ddi_power_enable_vddio_interrupt(true); } } break; case new_5v_disconnection: ddi_bc_SetDisable(); ddi_bc_SetCurrentLimit(0); if (info->regulator) regulator_set_current_limit(info->regulator, 0, 0); info->is_usb_online = 0; info->is_ac_online = 0; info->sm_5v_connection_status = _5v_disconnected_unverified; case existing_5v_disconnection: if (info->sm_5v_connection_status != _5v_disconnected_verified) { if ((jiffies - info->sm_new_5v_disconnection_jiffies) < 0) { info->sm_new_5v_connection_jiffies = jiffies; break; } if ((jiffies_to_msecs(jiffies - info->sm_new_5v_disconnection_jiffies)) > _5V_DEBOUNCE_TIME_MS) { info->sm_5v_connection_status = _5v_disconnected_verified; ddi_power_execute_5v_to_battery_handoff(); ddi_power_enable_5v_connect_detection(); /* part of handling for errata. * It is now safe to * turn on vddio interrupts again */ ddi_power_enable_vddio_interrupt(true); dev_info(info->dev, "5v disconnection handled\n"); } } break; } }
/* Send adtc command to the card */ static void stmp3xxx_mmc_adtc(struct stmp3xxx_mmc_host *host) { struct mmc_command *cmd = host->cmd; struct stmp3xxx_dma_descriptor *dma_desc = &host->dma_desc; int ignore_crc, resp, long_resp; int is_reading = 0; unsigned int copy_size; u32 ssp_ctrl0; u32 ssp_cmd0; u32 ssp_cmd1; u32 timeout; u32 val; u32 data_size = cmd->data->blksz * cmd->data->blocks; u32 log2_block_size; ignore_crc = mmc_resp_type(cmd) & MMC_RSP_CRC ? 0 : 1; resp = mmc_resp_type(cmd) & MMC_RSP_PRESENT ? 1 : 0; long_resp = mmc_resp_type(cmd) & MMC_RSP_136 ? 1 : 0; dev_dbg(host->dev, "ADTC command:\n" "response: %d, ignore crc: %d\n" "data list: %u, blocksz: %u, blocks: %u, timeout: %uns %uclks, " "flags: 0x%x\n", resp, ignore_crc, cmd->data->sg_len, cmd->data->blksz, cmd->data->blocks, cmd->data->timeout_ns, cmd->data->timeout_clks, cmd->data->flags); if (cmd->data->flags & MMC_DATA_WRITE) { dev_dbg(host->dev, "Data Write\n"); copy_size = stmp3xxx_sg_dma_copy(host, data_size, 1); BUG_ON(copy_size < data_size); is_reading = 0; if (!host->regulator) __init_reg(host->dev, &host->regulator); if (host->regulator) regulator_set_current_limit(host->regulator, host->write_uA, host->write_uA); } else if (cmd->data->flags & MMC_DATA_READ) { dev_dbg(host->dev, "Data Read\n"); is_reading = 1; if (!host->regulator) __init_reg(host->dev, &host->regulator); if (host->regulator) regulator_set_current_limit(host->regulator, host->read_uA, host->read_uA); } else { dev_warn(host->dev, "Unsuspported data mode, 0x%x\n", cmd->data->flags); BUG(); } BUG_ON(cmd->data->flags & MMC_DATA_STREAM); BUG_ON((data_size % 8) > 0); dma_desc->command->cmd = BM_APBH_CHn_CMD_WAIT4ENDCMD | BM_APBH_CHn_CMD_SEMAPHORE | BM_APBH_CHn_CMD_IRQONCMPLT | BF(data_size, APBH_CHn_CMD_XFER_COUNT) | BF(3, APBH_CHn_CMD_CMDWORDS); /* when is_reading is set, DMA controller performs WRITE operation. */ dma_desc->command->cmd |= BF(is_reading ? BV_APBH_CHn_CMD_COMMAND__DMA_WRITE : BV_APBH_CHn_CMD_COMMAND__DMA_READ, APBH_CHn_CMD_COMMAND); ssp_ctrl0 = (ignore_crc ? BM_SSP_CTRL0_IGNORE_CRC : 0) | (resp ? BM_SSP_CTRL0_GET_RESP : 0) | (long_resp ? BM_SSP_CTRL0_LONG_RESP : 0) | (is_reading ? BM_SSP_CTRL0_READ : 0) | BM_SSP_CTRL0_DATA_XFER | BM_SSP_CTRL0_WAIT_FOR_IRQ | BM_SSP_CTRL0_ENABLE | BF(data_size, SSP_CTRL0_XFER_COUNT) | BF(host->bus_width_4 ? BV_SSP_CTRL0_BUS_WIDTH__FOUR_BIT : BV_SSP_CTRL0_BUS_WIDTH__ONE_BIT, SSP_CTRL0_BUS_WIDTH); /* * We need to set the hardware register to the logarithm to base 2 of * the block size. */ log2_block_size = ilog2(cmd->data->blksz); ssp_cmd0 = BF(log2_block_size, SSP_CMD0_BLOCK_SIZE) | BF(cmd->opcode, SSP_CMD0_CMD) | BF(cmd->data->blocks - 1, SSP_CMD0_BLOCK_COUNT); if (cmd->opcode == 12) ssp_cmd0 |= BM_SSP_CMD0_APPEND_8CYC; ssp_cmd1 = BF(cmd->arg, SSP_CMD1_CMD_ARG); dma_desc->command->pio_words[0] = ssp_ctrl0; dma_desc->command->pio_words[1] = ssp_cmd0; dma_desc->command->pio_words[2] = ssp_cmd1; /* Set the timeout count */ timeout = stmp3xxx_ns_to_ssp_ticks(host->clkrt, cmd->data->timeout_ns); val = __raw_readl(host->ssp_base + HW_SSP_TIMING); val &= ~(BM_SSP_TIMING_TIMEOUT); val |= BF(timeout, SSP_TIMING_TIMEOUT); __raw_writel(val, host->ssp_base + HW_SSP_TIMING); init_completion(&host->dma_done); stmp3xxx_dma_reset_channel(host->dmach); stmp3xxx_dma_go(host->dmach, dma_desc, 1); wait_for_completion(&host->dma_done); if (host->regulator) regulator_set_current_limit(host->regulator, 0, 0); switch (mmc_resp_type(cmd)) { case MMC_RSP_NONE: break; case MMC_RSP_R1: case MMC_RSP_R3: cmd->resp[0] = __raw_readl(host->ssp_base + HW_SSP_SDRESP0); break; case MMC_RSP_R2: cmd->resp[3] = __raw_readl(host->ssp_base + HW_SSP_SDRESP0); cmd->resp[2] = __raw_readl(host->ssp_base + HW_SSP_SDRESP1); cmd->resp[1] = __raw_readl(host->ssp_base + HW_SSP_SDRESP2); cmd->resp[0] = __raw_readl(host->ssp_base + HW_SSP_SDRESP3); break; default: dev_warn(host->dev, "Unsupported response type 0x%x\n", mmc_resp_type(cmd)); BUG(); break; } cmd->error = stmp3xxx_mmc_cmd_error(host->status); if (stmp3xxx_dma_running(host->dmach)) dev_dbg(host->dev, "DMA command not finished\n"); if (cmd->error) { dev_dbg(host->dev, "Command error 0x%x\n", cmd->error); stmp3xxx_dma_reset_channel(host->dmach); } else { if (is_reading) cmd->data->bytes_xfered = stmp3xxx_sg_dma_copy(host, data_size, 0); else cmd->data->bytes_xfered = data_size; dev_dbg(host->dev, "Transferred %u bytes\n", cmd->data->bytes_xfered); } }