static bool bln_timeout_expired(void) { if (bln_notification_timeout && _ktime_compare(alarm_get_elapsed_realtime(), bln_end_time) >= 0) { printk("bln: ending by timeout\n"); bln_on = false; return true; } DEBUG_LOG("remain: %lldns", ktime_sub(bln_end_time, alarm_get_elapsed_realtime()).tv64); return false; }
static ssize_t pm8xxx_led_off_timer_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct led_classdev *led_cdev; struct pm8xxx_led_data *ldata; int min, sec; uint16_t off_timer; ktime_t interval; ktime_t next_alarm; min = -1; sec = -1; sscanf(buf, "%d %d", &min, &sec); if (min < 0 || min > 255) return -EINVAL; if (sec < 0 || sec > 255) return -EINVAL; led_cdev = (struct led_classdev *) dev_get_drvdata(dev); ldata = container_of(led_cdev, struct pm8xxx_led_data, cdev); LED_INFO("Setting %s off_timer to %d min %d sec \n", led_cdev->name, min, sec); off_timer = min * 60 + sec; alarm_cancel(&ldata->led_alarm); cancel_work_sync(&ldata->led_work); if (off_timer) { interval = ktime_set(off_timer, 0); next_alarm = ktime_add(alarm_get_elapsed_realtime(), interval); alarm_start_range(&ldata->led_alarm, next_alarm, next_alarm); } return count; }
static void s3c_bat_work(struct work_struct *work) { struct chg_data *chg = container_of(work, struct chg_data, bat_work); int ret; struct timespec ts; unsigned long flags; mutex_lock(&chg->mutex); s3c_bat_discharge_reason(chg); ret = s3c_cable_status_update(chg); if (ret < 0) goto err; mutex_unlock(&chg->mutex); power_supply_changed(&chg->psy_bat); chg->last_poll = alarm_get_elapsed_realtime(); ts = ktime_to_timespec(chg->last_poll); chg->timestamp = ts.tv_sec; /* prevent suspend before starting the alarm */ local_irq_save(flags); wake_unlock(&chg->work_wake_lock); s3c_program_alarm(chg, FAST_POLL); local_irq_restore(flags); return; err: mutex_unlock(&chg->mutex); wake_unlock(&chg->work_wake_lock); pr_err("battery workqueue fail\n"); }
static void bln_init_timeout(void) { if (bln_enabled && bln_notification_timeout && !bln_ongoing) { DEBUG_LOG("seconds: %u, bln_on: %d", bln_notification_timeout, bln_on); bln_end_time = ktime_add(alarm_get_elapsed_realtime(), ktime_set(bln_notification_timeout * 60, 0)); } else DEBUG_LOG("bailing: enabled: %d, timeout: %d, ongoing: %d", bln_enabled, bln_notification_timeout, bln_ongoing); }
static void thermal_rtc_callback(struct alarm *al) { struct timeval ts; ts = ktime_to_timeval(alarm_get_elapsed_realtime()); schedule_work(&timer_work); pr_debug("%s: Time on alarm expiry: %ld %ld\n", KBUILD_MODNAME, ts.tv_sec, ts.tv_usec); }
static void set_alarm(struct max77665_charger *chg, int seconds) { ktime_t interval = ktime_set(seconds, 0); ktime_t now = alarm_get_elapsed_realtime(); ktime_t next = ktime_add(now, interval); pr_info("set alarm after %d seconds\n", seconds); alarm_start_range(&chg->alarm, next, next); }
static void tps65200_set_check_alarm(void) { ktime_t interval; ktime_t next_alarm; interval = ktime_set(TPS65200_CHECK_INTERVAL, 0); next_alarm = ktime_add(alarm_get_elapsed_realtime(), interval); alarm_start_range(&tps65200_check_alarm, next_alarm, next_alarm); }
static void wakefunc_rtc_callback(struct alarm *al) { struct timeval ts; ts = ktime_to_timeval(alarm_get_elapsed_realtime()); wake_pwrtrigger(); pr_debug("%s: Time of alarm expiry: %ld\n", WAKEFUNC, ts.tv_sec); }
static void s3c_bat_discharge_reason(struct chg_data *chg) { int discharge_reason; ktime_t ktime; struct timespec cur_time; discharge_reason = chg->bat_info.dis_reason & 0xf; if(chg->bat_info.batt_percentage >= 100) { chg->set_batt_full = 1; chg->bat_info.batt_is_full = true; } if (discharge_reason & DISCONNECT_BAT_FULL && /*chg->bat_info.batt_vcell < RECHARGE_COND_VOLTAGE*/ chg->bat_info.batt_percentage < 100) chg->bat_info.dis_reason &= ~DISCONNECT_BAT_FULL; if (discharge_reason & DISCONNECT_TEMP_OVERHEAT && chg->bat_info.batt_temp <= HIGH_RECOVER_TEMP) chg->bat_info.dis_reason &= ~DISCONNECT_TEMP_OVERHEAT; if (discharge_reason & DISCONNECT_TEMP_FREEZE && chg->bat_info.batt_temp >= LOW_RECOVER_TEMP) chg->bat_info.dis_reason &= ~DISCONNECT_TEMP_FREEZE; if (discharge_reason & DISCONNECT_OVER_TIME && /*chg->bat_info.batt_vcell < RECHARGE_COND_VOLTAGE*/ chg->bat_info.batt_percentage < 100) chg->bat_info.dis_reason &= ~DISCONNECT_OVER_TIME; if (chg->set_batt_full) chg->bat_info.dis_reason |= DISCONNECT_BAT_FULL; if (chg->bat_info.batt_health != POWER_SUPPLY_HEALTH_GOOD) chg->bat_info.dis_reason |= chg->bat_info.batt_health == POWER_SUPPLY_HEALTH_OVERHEAT ? DISCONNECT_TEMP_OVERHEAT : DISCONNECT_TEMP_FREEZE; ktime = alarm_get_elapsed_realtime(); cur_time = ktime_to_timespec(ktime); if (chg->discharging_time && cur_time.tv_sec > chg->discharging_time) { chg->set_charge_timeout = true; chg->bat_info.dis_reason |= DISCONNECT_OVER_TIME; } pr_debug("%s : Current charge level : %d%%\n\ Current time : %ld discharging_time : %ld\n\ discharging reason : %d\n",\ __func__, chg->bat_info.batt_percentage, cur_time.tv_sec, chg->discharging_time, chg->bat_info.dis_reason); }
static int instinctq_battery_prepare(struct device *dev) { struct instinctq_battery *bat = dev_get_drvdata(dev); ktime_t now, start, end; #ifdef CONFIG_RTC_INTF_ALARM now = alarm_get_elapsed_realtime(); start = ktime_set(SUSPEND_INTERVAL - 10, 0); start = ktime_add(now, start); end = ktime_set(SUSPEND_INTERVAL + 10, 0); end = ktime_add(now, end); alarm_start_range(&bat->alarm, start, end); #endif return 0; }
static void sec_set_time_for_charging(struct sec_bat_info *info, int mode) { if (mode) { ktime_t ktime; struct timespec cur_time; ktime = alarm_get_elapsed_realtime(); cur_time = ktime_to_timespec(ktime); /* record start time for abs timer */ info->charging_start_time = cur_time.tv_sec; } else { /* initialize start time for abs timer */ info->charging_start_time = 0; } }
static void p3_set_time_for_charging(struct battery_data *battery, int mode) { if (mode) { ktime_t ktime; struct timespec cur_time; ktime = alarm_get_elapsed_realtime(); cur_time = ktime_to_timespec(ktime); /* record start time for abs timer */ battery->charging_start_time = cur_time.tv_sec; } else { /* initialize start time for abs timer */ battery->charging_start_time = 0; } }
static void p3_bat_work(struct work_struct *work) { struct battery_data *battery = container_of(work, struct battery_data, battery_work); unsigned long flags; pr_debug("bat work "); p3_bat_status_update(&battery->psy_battery); battery->last_poll = alarm_get_elapsed_realtime(); /* prevent suspend before starting the alarm */ local_irq_save(flags); wake_unlock(&battery->work_wake_lock); p3_program_alarm(battery, FAST_POLL); local_irq_restore(flags); }
static int sec_is_over_abs_time(struct sec_bat_info *info, unsigned int abs_time) { ktime_t ktime; struct timespec cur_time; if (!info->charging_start_time) return 0; ktime = alarm_get_elapsed_realtime(); cur_time = ktime_to_timespec(ktime); if (info->charging_start_time + abs_time < cur_time.tv_sec) { pr_info("Charging time out"); return 1; } else return 0; }
static irqreturn_t sensordata_irq_thread_fn(int iIrq, void *dev_id) { struct ssp_data *data = dev_id; struct timespec ts; ts = ktime_to_timespec(alarm_get_elapsed_realtime()); data->timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec; if(gpio_get_value(data->mcu_int1)) { pr_info("[SSP] MCU int HIGH"); return IRQ_HANDLED; } select_irq_msg(data); data->uIrqCnt++; return IRQ_HANDLED; }
static void thermal_rtc_setup(void) { ktime_t wakeup_time; ktime_t curr_time; curr_time = alarm_get_elapsed_realtime(); wakeup_time = ktime_add_us(curr_time, (wakeup_ms * USEC_PER_MSEC)); alarm_start_range(&thermal_rtc, wakeup_time, wakeup_time); pr_debug("%s: Current Time: %ld %ld, Alarm set to: %ld %ld\n", KBUILD_MODNAME, ktime_to_timeval(curr_time).tv_sec, ktime_to_timeval(curr_time).tv_usec, ktime_to_timeval(wakeup_time).tv_sec, ktime_to_timeval(wakeup_time).tv_usec); }
static void sec_bat_cable_work(struct work_struct *work) { struct sec_bat_info *info = container_of(work, struct sec_bat_info, cable_work); switch (info->cable_type) { case CABLE_TYPE_NONE: info->batt_full_status = BATT_NOT_FULL; info->recharging_status = false; info->charging_start_time = 0; info->batt_temp_high_cnt = 0; info->batt_temp_low_cnt = 0; info->batt_temp_recover_cnt = 0; info->charging_status = POWER_SUPPLY_STATUS_DISCHARGING; sec_bat_enable_charging(info, false); if (info->batt_health == POWER_SUPPLY_HEALTH_OVERVOLTAGE) info->batt_health = POWER_SUPPLY_HEALTH_GOOD; wake_lock_timeout(&info->vbus_wake_lock, HZ * 2); break; case CABLE_TYPE_USB: info->charging_status = POWER_SUPPLY_STATUS_CHARGING; sec_bat_enable_charging(info, true); wake_lock(&info->vbus_wake_lock); break; case CABLE_TYPE_AC: case CABLE_TYPE_DOCK: info->charging_status = POWER_SUPPLY_STATUS_CHARGING; sec_bat_enable_charging(info, true); break; default: dev_err(info->dev, "%s: Invalid cable type\n", __func__); break;; } power_supply_changed(&info->psy_ac); power_supply_changed(&info->psy_usb); info->last_poll = alarm_get_elapsed_realtime(); sec_program_alarm(info, FAST_POLL); /* To notify framework layer, remaning 2 sec */ wake_lock_timeout(&info->cable_wake_lock, HZ * 2); }
static bool bln_start_blinking_ex(bool start, unsigned int timeout_ms) { DEBUG_LOG("start: %d, bln_enabled: %d, bln_on: %d", start, bln_enabled, bln_on); if (start) { ktime_t delay; if (!bln_enabled || !bln_on) return false; bln_blink_on = true; delay = ktime_add(alarm_get_elapsed_realtime(), ktime_set(timeout_ms/1000, 0)); alarm_start_range(&bln_blink_alarm, delay, delay); return true; } else { bln_blink_on = false; alarm_try_to_cancel(&bln_blink_alarm); cancel_delayed_work(&bln_blink_work); if (wake_lock_active(&bln_blink_wakelock)) wake_unlock(&bln_blink_wakelock); return false; } }
static void battery_monitor_interval(struct battery_info *info) { ktime_t interval, next, slack; unsigned long flags; pr_debug("%s\n", __func__); local_irq_save(flags); info->last_poll = alarm_get_elapsed_realtime(); switch (info->monitor_mode) { case MONITOR_CHNG: info->monitor_interval = info->pdata->chng_interval; break; case MONITOR_CHNG_SUSP: info->monitor_interval = info->pdata->chng_susp_interval; break; case MONITOR_NORM: info->monitor_interval = info->pdata->norm_interval; break; case MONITOR_NORM_SUSP: info->monitor_interval = info->pdata->norm_susp_interval; break; case MONITOR_EMER: info->monitor_interval = info->pdata->emer_interval; break; default: info->monitor_interval = info->pdata->norm_interval; break; } pr_debug("%s: monitor mode(%d), interval(%d)\n", __func__, info->monitor_mode, info->monitor_interval); interval = ktime_set(info->monitor_interval, 0); next = ktime_add(info->last_poll, interval); slack = ktime_set(20, 0); alarm_start_range(&info->alarm, next, ktime_add(next, slack)); local_irq_restore(flags); }
static void ds2746_battery_work(struct work_struct *work) { struct ds2746_device_info *di = container_of(work, struct ds2746_device_info, monitor_work); unsigned long flags; do_power_alg(0); get_state_check_interval_min_sec(); di->last_poll = alarm_get_elapsed_realtime(); /* prevent suspend before starting the alarm */ local_irq_save(flags); wake_unlock(&di->work_wake_lock); if (poweralg.battery.is_prediction) ds2746_program_alarm(di, PREDIC_POLL); else ds2746_program_alarm(di, FAST_POLL); local_irq_restore(flags); }
static void wakefunc_rtc_start(void) { ktime_t wakeup_time; ktime_t curr_time; if (!dt2w_switch && !s2w_switch) return; wakefunc_triggered = false; curr_time = alarm_get_elapsed_realtime(); wakeup_time = ktime_add_us(curr_time, (wake_timeout * 1000LL * 60000LL)); alarm_start_range(&wakefunc_rtc, wakeup_time, wakeup_time); pr_info("%s: Current Time: %ld, Alarm set to: %ld\n", WAKEFUNC, ktime_to_timeval(curr_time).tv_sec, ktime_to_timeval(wakeup_time).tv_sec); pr_info("%s: Timeout started for %llu minutes\n", WAKEFUNC, wake_timeout); }
static void p3_cable_changed(struct battery_data *battery) { pr_debug("charger changed "); if (!battery->p3_battery_initial) return; if (!battery->charging_mode_booting) battery->info.batt_is_full = 0; battery->info.batt_health = POWER_SUPPLY_HEALTH_GOOD; schedule_work(&battery->cable_work); /* * Wait a bit before reading ac/usb line status and setting charger, * because ac/usb status readings may lag from irq. */ battery->last_poll = alarm_get_elapsed_realtime(); p3_program_alarm(battery, FAST_POLL); }
static int is_over_abs_time(struct battery_data *battery) { unsigned int total_time; ktime_t ktime; struct timespec cur_time; if (!battery->charging_start_time) return 0; ktime = alarm_get_elapsed_realtime(); cur_time = ktime_to_timespec(ktime); if (battery->info.batt_is_recharging) total_time = battery->pdata->recharge_duration; else total_time = battery->pdata->charge_duration; if (battery->charging_start_time + total_time < cur_time.tv_sec) { pr_info("Charging time out"); return 1; } else return 0; }
int battery_info_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data) { struct battery_info *info = data; struct timespec cur_time; ktime_t ktime; int len = 0; /* Guess we need no more than 100 bytes. */ int size = 100; ktime = alarm_get_elapsed_realtime(); cur_time = ktime_to_timespec(ktime); len = snprintf(buf, size, "%lu\t%u\t%u\t%u\t%u\t%d\t%u\t%d\t%d\t%u\t" "%u\t%u\t%u\t%u\t%u\t%u\t%d\t%u\t%u\n", cur_time.tv_sec, info->battery_raw_soc, info->battery_soc, info->battery_vcell / 1000, info->battery_vfocv / 1000, info->battery_full_soc, info->battery_present, info->battery_temper, info->battery_temper_adc, info->battery_health, info->charge_real_state, info->charge_virt_state, info->cable_type, info->charge_current, info->full_charged_state, info->recharge_phase, info->abstimer_state, info->monitor_interval, info->charge_start_time); return len; }
static bool battery_abstimer_cond(struct battery_info *info) { unsigned int abstimer_duration; ktime_t ktime; struct timespec current_time; pr_debug("%s\n", __func__); if ((info->cable_type != POWER_SUPPLY_TYPE_MAINS) || (info->full_charged_state == true) || (info->charge_start_time == 0)) { info->abstimer_state = false; return false; } ktime = alarm_get_elapsed_realtime(); current_time = ktime_to_timespec(ktime); if (info->recharge_phase) abstimer_duration = info->pdata->abstimer_recharge_duration; else abstimer_duration = info->pdata->abstimer_charge_duration; if ((current_time.tv_sec - info->charge_start_time) > abstimer_duration) { pr_info("%s: charge time out(%d - %d ?? %d)\n", __func__, (int)current_time.tv_sec, info->charge_start_time, abstimer_duration); info->abstimer_state = true; } else { pr_debug("%s: not abstimer condition\n", __func__); info->abstimer_state = false; } return info->abstimer_state; }
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int rv = 0; unsigned long flags; struct timespec new_alarm_time; struct timespec new_rtc_time; struct timespec tmp_time; enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd); uint32_t alarm_type_mask = 1U << alarm_type; if (alarm_type >= ANDROID_ALARM_TYPE_COUNT) return -EINVAL; #ifdef CONFIG_ANDROID_RTC_CHANGE_WAIT if( ANDROID_ALARM_BASE_CMD(cmd)!=ANDROID_ALARM_GET_TIME(0) && ANDROID_ALARM_BASE_CMD(cmd)!=ANDROID_RTC_CHANGE_WAIT ){ #else if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) { #endif if ((file->f_flags & O_ACCMODE) == O_RDONLY) return -EPERM; if (file->private_data == NULL && cmd != ANDROID_ALARM_SET_RTC) { spin_lock_irqsave(&alarm_slock, flags); if (alarm_opened) { spin_unlock_irqrestore(&alarm_slock, flags); return -EBUSY; } alarm_opened = 1; file->private_data = (void *)1; spin_unlock_irqrestore(&alarm_slock, flags); } } switch (ANDROID_ALARM_BASE_CMD(cmd)) { case ANDROID_ALARM_CLEAR(0): spin_lock_irqsave(&alarm_slock, flags); pr_alarm(IO, "alarm %d clear\n", alarm_type); alarm_try_to_cancel(&alarms[alarm_type]); if (alarm_pending) { alarm_pending &= ~alarm_type_mask; if (!alarm_pending && !wait_pending) wake_unlock(&alarm_wake_lock); } alarm_enabled &= ~alarm_type_mask; spin_unlock_irqrestore(&alarm_slock, flags); break; case ANDROID_ALARM_SET_OLD: case ANDROID_ALARM_SET_AND_WAIT_OLD: if (get_user(new_alarm_time.tv_sec, (int __user *)arg)) { rv = -EFAULT; goto err1; } new_alarm_time.tv_nsec = 0; goto from_old_alarm_set; case ANDROID_ALARM_SET_AND_WAIT(0): case ANDROID_ALARM_SET(0): if (copy_from_user(&new_alarm_time, (void __user *)arg, sizeof(new_alarm_time))) { rv = -EFAULT; goto err1; } from_old_alarm_set: spin_lock_irqsave(&alarm_slock, flags); pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type, new_alarm_time.tv_sec, new_alarm_time.tv_nsec); alarm_enabled |= alarm_type_mask; alarm_start_range(&alarms[alarm_type], timespec_to_ktime(new_alarm_time), timespec_to_ktime(new_alarm_time)); spin_unlock_irqrestore(&alarm_slock, flags); if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0) && cmd != ANDROID_ALARM_SET_AND_WAIT_OLD) break; /* fall though */ case ANDROID_ALARM_WAIT: spin_lock_irqsave(&alarm_slock, flags); pr_alarm(IO, "alarm wait\n"); if (!alarm_pending && wait_pending) { wake_unlock(&alarm_wake_lock); wait_pending = 0; } spin_unlock_irqrestore(&alarm_slock, flags); rv = wait_event_interruptible(alarm_wait_queue, alarm_pending); if (rv) goto err1; spin_lock_irqsave(&alarm_slock, flags); rv = alarm_pending; wait_pending = 1; alarm_pending = 0; spin_unlock_irqrestore(&alarm_slock, flags); break; #ifdef CONFIG_ANDROID_RTC_CHANGE_WAIT case ANDROID_RTC_CHANGE_WAIT: rv = wait_event_interruptible(rtc_change_wait_queue, rtc_changed); spin_lock_irqsave(&alarm_slock, flags); rtc_changed = 0; spin_unlock_irqrestore(&alarm_slock, flags); if (rv) goto err1; break; #endif case ANDROID_ALARM_SET_RTC: if (copy_from_user(&new_rtc_time, (void __user *)arg, sizeof(new_rtc_time))) { rv = -EFAULT; goto err1; } rv = alarm_set_rtc(new_rtc_time); spin_lock_irqsave(&alarm_slock, flags); alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK; wake_up(&alarm_wait_queue); #ifdef CONFIG_ANDROID_RTC_CHANGE_WAIT rtc_changed = 1; wake_up(&rtc_change_wait_queue); #endif spin_unlock_irqrestore(&alarm_slock, flags); if (rv < 0) goto err1; break; case ANDROID_ALARM_GET_TIME(0): switch (alarm_type) { case ANDROID_ALARM_RTC_WAKEUP: case ANDROID_ALARM_RTC: getnstimeofday(&tmp_time); break; case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP: case ANDROID_ALARM_ELAPSED_REALTIME: tmp_time = ktime_to_timespec(alarm_get_elapsed_realtime()); break; case ANDROID_ALARM_TYPE_COUNT: case ANDROID_ALARM_SYSTEMTIME: ktime_get_ts(&tmp_time); break; } if (copy_to_user((void __user *)arg, &tmp_time, sizeof(tmp_time))) { rv = -EFAULT; goto err1; } break; default: rv = -EINVAL; goto err1; } err1: return rv; } static int alarm_open(struct inode *inode, struct file *file) { file->private_data = NULL; return 0; }
static __devinit int samsung_battery_probe(struct platform_device *pdev) { struct battery_info *info; int ret = 0; char *temper_src_name[] = { "fuelgauge", "ap adc", "ext adc", "unknown" }; pr_info("%s: SAMSUNG Battery Driver Loading\n", __func__); info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; platform_set_drvdata(pdev, info); info->dev = &pdev->dev; info->pdata = pdev->dev.platform_data; /* Check charger name and fuelgauge name. */ if (!info->pdata->charger_name || !info->pdata->fuelgauge_name) { pr_err("%s: no charger or fuel gauge name\n", __func__); goto err_kfree; } info->charger_name = info->pdata->charger_name; info->fuelgauge_name = info->pdata->fuelgauge_name; #if defined(CONFIG_CHARGER_MAX8922_U1) if (system_rev >= 2) info->sub_charger_name = info->pdata->sub_charger_name; #endif pr_info("%s: Charger name: %s\n", __func__, info->charger_name); pr_info("%s: Fuelgauge name: %s\n", __func__, info->fuelgauge_name); #if defined(CONFIG_CHARGER_MAX8922_U1) if (system_rev >= 2) pr_info("%s: SubCharger name: %s\n", __func__, info->sub_charger_name); #endif info->psy_charger = power_supply_get_by_name(info->charger_name); info->psy_fuelgauge = power_supply_get_by_name(info->fuelgauge_name); #if defined(CONFIG_CHARGER_MAX8922_U1) if (system_rev >= 2) info->psy_sub_charger = power_supply_get_by_name(info->sub_charger_name); #endif if (!info->psy_charger || !info->psy_fuelgauge) { pr_err("%s: fail to get power supply\n", __func__); goto err_kfree; } /* WORKAROUND: set battery pdata in driver */ if (system_rev == 3) { info->pdata->temper_src = TEMPER_EXT_ADC; info->pdata->temper_ch = 7; } pr_info("%s: Temperature source: %s\n", __func__, temper_src_name[info->pdata->temper_src]); /* recalculate recharge voltage, it depends on max voltage value */ info->pdata->recharge_voltage = info->pdata->voltage_max - 50; pr_info("%s: Recharge voltage: %d\n", __func__, info->pdata->recharge_voltage); #if defined(CONFIG_S3C_ADC) #if defined(CONFIG_MACH_S2PLUS) if (system_rev >= 2) #endif /* adc register */ info->adc_client = s3c_adc_register(pdev, NULL, NULL, 0); #endif /* init battery info */ info->full_charged_state = false; info->abstimer_state = false; info->recharge_phase = false; info->siop_charge_current = CHARGER_USB_CURRENT; info->monitor_mode = MONITOR_NORM; info->led_state = BATT_LED_DISCHARGING; /* LPM charging state */ info->lpm_state = lpcharge; wake_lock_init(&info->monitor_wake_lock, WAKE_LOCK_SUSPEND, "battery-monitor"); wake_lock_init(&info->emer_wake_lock, WAKE_LOCK_SUSPEND, "battery-emergency"); if (!info->pdata->suspend_chging) wake_lock_init(&info->charge_wake_lock, WAKE_LOCK_SUSPEND, "battery-charging"); /* Init wq for battery */ INIT_WORK(&info->error_work, battery_error_work); INIT_WORK(&info->monitor_work, battery_monitor_work); /* Init Power supply class */ info->psy_bat.name = "battery"; info->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY; info->psy_bat.properties = samsung_battery_props; info->psy_bat.num_properties = ARRAY_SIZE(samsung_battery_props); info->psy_bat.get_property = samsung_battery_get_property; info->psy_bat.set_property = samsung_battery_set_property; info->psy_usb.name = "usb"; info->psy_usb.type = POWER_SUPPLY_TYPE_USB; info->psy_usb.supplied_to = supply_list; info->psy_usb.num_supplicants = ARRAY_SIZE(supply_list); info->psy_usb.properties = samsung_power_props; info->psy_usb.num_properties = ARRAY_SIZE(samsung_power_props); info->psy_usb.get_property = samsung_usb_get_property; info->psy_ac.name = "ac"; info->psy_ac.type = POWER_SUPPLY_TYPE_MAINS; info->psy_ac.supplied_to = supply_list; info->psy_ac.num_supplicants = ARRAY_SIZE(supply_list); info->psy_ac.properties = samsung_power_props; info->psy_ac.num_properties = ARRAY_SIZE(samsung_power_props); info->psy_ac.get_property = samsung_ac_get_property; ret = power_supply_register(&pdev->dev, &info->psy_bat); if (ret) { pr_err("%s: failed to register psy_bat\n", __func__); goto err_psy_reg_bat; } ret = power_supply_register(&pdev->dev, &info->psy_usb); if (ret) { pr_err("%s: failed to register psy_usb\n", __func__); goto err_psy_reg_usb; } ret = power_supply_register(&pdev->dev, &info->psy_ac); if (ret) { pr_err("%s: failed to register psy_ac\n", __func__); goto err_psy_reg_ac; } /* Using android alarm for gauging instead of workqueue */ info->last_poll = alarm_get_elapsed_realtime(); alarm_init(&info->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, samsung_battery_alarm_start); /* update battery init status */ schedule_work(&info->monitor_work); /* Create samsung detail attributes */ battery_create_attrs(info->psy_bat.dev); pr_info("%s: SAMSUNG Battery Driver Loaded\n", __func__); return 0; err_psy_reg_ac: power_supply_unregister(&info->psy_usb); err_psy_reg_usb: power_supply_unregister(&info->psy_bat); err_psy_reg_bat: wake_lock_destroy(&info->monitor_wake_lock); wake_lock_destroy(&info->emer_wake_lock); if (!info->pdata->suspend_chging) wake_lock_destroy(&info->charge_wake_lock); err_kfree: kfree(info); return ret; }
static __devinit int max8998_charger_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); struct chg_data *chg; struct i2c_client *i2c = iodev->i2c; int ret = 0; pr_info("%s : MAX8998 Charger Driver Loading\n", __func__); chg = kzalloc(sizeof(*chg), GFP_KERNEL); if (!chg) return -ENOMEM; chg->iodev = iodev; chg->pdata = pdata->charger; if (!chg->pdata || !chg->pdata->adc_table) { pr_err("%s : No platform data & adc_table supplied\n", __func__); ret = -EINVAL; goto err_bat_table; } chg->psy_bat.name = "battery", chg->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY, chg->psy_bat.properties = max8998_battery_props, chg->psy_bat.num_properties = ARRAY_SIZE(max8998_battery_props), chg->psy_bat.get_property = s3c_bat_get_property, chg->psy_bat.property_is_writeable = s3c_bat_property_is_writeable, chg->psy_bat.set_property = s3c_bat_set_property, chg->psy_usb.name = "usb", chg->psy_usb.type = POWER_SUPPLY_TYPE_USB, chg->psy_usb.supplied_to = supply_list, chg->psy_usb.num_supplicants = ARRAY_SIZE(supply_list), chg->psy_usb.properties = s3c_power_properties, chg->psy_usb.num_properties = ARRAY_SIZE(s3c_power_properties), chg->psy_usb.get_property = s3c_usb_get_property, chg->psy_ac.name = "ac", chg->psy_ac.type = POWER_SUPPLY_TYPE_MAINS, chg->psy_ac.supplied_to = supply_list, chg->psy_ac.num_supplicants = ARRAY_SIZE(supply_list), chg->psy_ac.properties = s3c_power_properties, chg->psy_ac.num_properties = ARRAY_SIZE(s3c_power_properties), chg->psy_ac.get_property = s3c_ac_get_property, chg->present = 1; chg->bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD; chg->bat_info.batt_is_full = false; chg->bat_info.batt_temp = 100; //fake chg->bat_info.batt_percentage = 50; //fake, modem will bootup soon and update it... hopefully chg->set_charge_timeout = false; chg->cable_status = CABLE_TYPE_NONE; mutex_init(&chg->mutex); platform_set_drvdata(pdev, chg); ret = max8998_update_reg(i2c, MAX8998_REG_CHGR1, /* disable */ (0x3 << MAX8998_SHIFT_RSTR), MAX8998_MASK_RSTR); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 6 Hr */ (0x2 << MAX8998_SHIFT_FT), MAX8998_MASK_FT); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 4.2V */ (0x0 << MAX8998_SHIFT_BATTSL), MAX8998_MASK_BATTSL); if (ret < 0) goto err_kfree; ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 105c */ (0x0 << MAX8998_SHIFT_TMP), MAX8998_MASK_TMP); if (ret < 0) goto err_kfree; pr_info("%s : pmic interrupt registered\n", __func__); ret = max8998_write_reg(i2c, MAX8998_REG_IRQM1, ~(MAX8998_MASK_DCINR | MAX8998_MASK_DCINF)); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM2, 0xFF); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, ~MAX8998_IRQ_CHGRSTF_MASK); if (ret < 0) goto err_kfree; ret = max8998_write_reg(i2c, MAX8998_REG_IRQM4, 0xFF); if (ret < 0) goto err_kfree; wake_lock_init(&chg->vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present"); wake_lock_init(&chg->work_wake_lock, WAKE_LOCK_SUSPEND, "max8998-charger"); INIT_WORK(&chg->bat_work, s3c_bat_work); chg->monitor_wqueue = create_freezable_workqueue(dev_name(&pdev->dev)); if (!chg->monitor_wqueue) { pr_err("Failed to create freezeable workqueue\n"); ret = -ENOMEM; goto err_wake_lock; } chg->last_poll = alarm_get_elapsed_realtime(); alarm_init(&chg->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, s3c_battery_alarm); check_lpm_charging_mode(chg); /* init power supplier framework */ ret = power_supply_register(&pdev->dev, &chg->psy_bat); if (ret) { pr_err("Failed to register power supply psy_bat\n"); goto err_wqueue; } ret = power_supply_register(&pdev->dev, &chg->psy_usb); if (ret) { pr_err("Failed to register power supply psy_usb\n"); goto err_supply_unreg_bat; } ret = power_supply_register(&pdev->dev, &chg->psy_ac); if (ret) { pr_err("Failed to register power supply psy_ac\n"); goto err_supply_unreg_usb; } ret = request_threaded_irq(iodev->i2c->irq, NULL, max8998_int_work_func, IRQF_TRIGGER_FALLING, "max8998-charger", chg); if (ret) { pr_err("%s : Failed to request pmic irq\n", __func__); goto err_supply_unreg_ac; } ret = enable_irq_wake(iodev->i2c->irq); if (ret) { pr_err("Failed to enable pmic irq wake\n"); goto err_irq; } ret = s3c_bat_create_attrs(chg->psy_bat.dev); if (ret) { pr_err("%s : Failed to create_attrs\n", __func__); goto err_irq; } chg->callbacks.set_cable = max8998_set_cable; if (chg->pdata->register_callbacks) chg->pdata->register_callbacks(&chg->callbacks); wake_lock(&chg->work_wake_lock); queue_work(chg->monitor_wqueue, &chg->bat_work); return 0; err_irq: free_irq(iodev->i2c->irq, NULL); err_supply_unreg_ac: power_supply_unregister(&chg->psy_ac); err_supply_unreg_usb: power_supply_unregister(&chg->psy_usb); err_supply_unreg_bat: power_supply_unregister(&chg->psy_bat); err_wqueue: destroy_workqueue(chg->monitor_wqueue); cancel_work_sync(&chg->bat_work); alarm_cancel(&chg->alarm); err_wake_lock: wake_lock_destroy(&chg->work_wake_lock); wake_lock_destroy(&chg->vbus_wake_lock); err_kfree: mutex_destroy(&chg->mutex); err_bat_table: kfree(chg); return ret; }
static void battery_charge_control(struct battery_info *info, int enable, int set_current) { ktime_t ktime; struct timespec current_time; pr_debug("%s\n", __func__); ktime = alarm_get_elapsed_realtime(); current_time = ktime_to_timespec(ktime); if (set_current == CHARGER_KEEP_CURRENT) goto charge_state_control; if (info->siop_state == true) { pr_debug("%s: siop state, charge current is %dmA\n", __func__, info->siop_charge_current); set_current = info->siop_charge_current; } /* check charge current before and after */ if (info->charge_current == ((set_current * 3 / 100) * 333 / 10)) { /* * (current * 3 / 100) is converted value * for register setting. * (register current * 333 / 10) is actual value * for charging */ pr_debug("%s: same charge current: %dmA\n", __func__, set_current); } else { battery_control_info(info, POWER_SUPPLY_PROP_CURRENT_NOW, set_current); pr_info("%s: update charge current: %dmA\n", __func__, set_current); } info->charge_current = battery_get_info(info, POWER_SUPPLY_PROP_CURRENT_NOW); charge_state_control: /* check charge state before and after */ if ((enable == CHARGE_ENABLE) && (info->charge_start_time == 0)) { battery_control_info(info, POWER_SUPPLY_PROP_STATUS, CHARGE_ENABLE); info->charge_start_time = current_time.tv_sec; pr_info("%s: charge enabled, current as %dmA @%d\n", __func__, info->charge_current, info->charge_start_time); } else if ((enable == CHARGE_DISABLE) && (info->charge_start_time != 0)) { battery_control_info(info, POWER_SUPPLY_PROP_STATUS, CHARGE_DISABLE); pr_info("%s: charge disabled, current as %dmA @%d\n", __func__, info->charge_current, (int)current_time.tv_sec); info->charge_start_time = 0; } else { pr_debug("%s: same charge state(%s), current as %dmA @%d\n", __func__, (enable ? "enabled" : "disabled"), info->charge_current, info->charge_start_time); } info->charge_real_state = info->charge_virt_state = battery_get_info(info, POWER_SUPPLY_PROP_STATUS); }
static int s3c_cable_status_update(struct chg_data *chg) { int ret; bool vdc_status; ktime_t ktime; struct timespec cur_time; /* if max8998 has detected vdcin */ if (max8998_check_vdcin(chg)) { vdc_status = 1; if (chg->bat_info.dis_reason) { pr_info("%s : battery status discharging : %d\n", __func__, chg->bat_info.dis_reason); /* have vdcin, but cannot charge */ chg->charging = false; ret = max8998_charging_control(chg); if (ret < 0) goto err; chg->bat_info.charging_status = chg->bat_info.batt_is_full ? POWER_SUPPLY_STATUS_FULL : POWER_SUPPLY_STATUS_NOT_CHARGING; chg->discharging_time = 0; chg->set_batt_full = 0; goto update; } else if (chg->discharging_time == 0) { ktime = alarm_get_elapsed_realtime(); cur_time = ktime_to_timespec(ktime); chg->discharging_time = chg->bat_info.batt_is_full || chg->set_charge_timeout ? cur_time.tv_sec + TOTAL_RECHARGING_TIME : cur_time.tv_sec + TOTAL_CHARGING_TIME; } /* able to charge */ chg->charging = true; ret = max8998_charging_control(chg); if (ret < 0) goto err; chg->bat_info.charging_status = chg->bat_info.batt_is_full ? POWER_SUPPLY_STATUS_FULL : POWER_SUPPLY_STATUS_CHARGING; } else { /* no vdc in, not able to charge */ vdc_status = 0; chg->charging = false; ret = max8998_charging_control(chg); if (ret < 0) goto err; chg->bat_info.charging_status = POWER_SUPPLY_STATUS_DISCHARGING; chg->bat_info.batt_is_full = false; chg->set_charge_timeout = false; chg->set_batt_full = 0; chg->bat_info.dis_reason = 0; chg->discharging_time = 0; if (lpm_charging_mode && pm_power_off) pm_power_off(); } update: if ((chg->cable_status == CABLE_TYPE_USB) && vdc_status) wake_lock(&chg->vbus_wake_lock); else wake_lock_timeout(&chg->vbus_wake_lock, HZ / 2); return 0; err: return ret; }