/* Detects a suspend and clears all the previous wake up reasons*/ static int wakeup_reason_pm_event(struct notifier_block *notifier, unsigned long pm_event, void *unused) { switch (pm_event) { case PM_SUSPEND_PREPARE: spin_lock(&resume_reason_lock); irqcount = 0; suspend_abort = false; mbox_wakeup = false; spin_unlock(&resume_reason_lock); /* monotonic time since boot */ last_monotime = ktime_get(); /* monotonic time since boot including the time spent in suspend */ last_stime = ktime_get_boottime(); break; case PM_POST_SUSPEND: /* monotonic time since boot */ curr_monotime = ktime_get(); /* monotonic time since boot including the time spent in suspend */ curr_stime = ktime_get_boottime(); break; default: break; } return NOTIFY_DONE; }
static void xyref5260_lcd_on(void) { s64 us = ktime_us_delta(lcd_on_time, ktime_get_boottime()); if (us > LCD_POWER_OFF_TIME_US) { pr_warn("lcd on sleep time too long\n"); us = LCD_POWER_OFF_TIME_US; } if (us > 0) usleep_range(us, us); s3c_gpio_setpull(EXYNOS5260_GPB2(0), S3C_GPIO_PULL_NONE); s3c_gpio_setpull(EXYNOS5260_GPD2(2), S3C_GPIO_PULL_NONE); gpio_request_one(EXYNOS5260_GPD2(2), GPIOF_OUT_INIT_HIGH, "GPD2"); usleep_range(5000, 6000); gpio_free(EXYNOS5260_GPD2(2)); #ifndef CONFIG_BACKLIGHT_PWM s3c_gpio_setpull(EXYNOS5260_GPD2(1), S3C_GPIO_PULL_NONE); gpio_request_one(EXYNOS5260_GPD2(1), GPIOF_OUT_INIT_HIGH, "GPD2"); usleep_range(5000, 6000); gpio_free(EXYNOS5260_GPD2(1)); #endif }
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(ktime_get_boottime()); data->timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec; #if defined SSP_IRQ_EDGE_PROTECT if (prevent_irq != 0) { select_irq_msg(data); data->uIrqCnt++; #if SSP_STATUS_MONITOR data->uSubIrqCnt++; #endif } else pr_err("[SSP] %s, irq Occured while Boot.\n", __func__); #else if (gpio_get_value(data->mcu_int1)) { pr_info("[SSP] MCU int HIGH"); return IRQ_HANDLED; } select_irq_msg(data); data->uIrqCnt++; #if SSP_STATUS_MONITOR data->uSubIrqCnt++; #endif #endif return IRQ_HANDLED; }
static inline s64 yas_iio_get_boottime_ns(void) { struct timespec ts; ts = ktime_to_timespec(ktime_get_boottime()); return timespec_to_ns(&ts); }
u64 fimc_is_get_timestamp_boot(void) { struct timespec curtime; curtime = ktime_to_timespec(ktime_get_boottime()); return (u64)curtime.tv_sec*1000000000 + curtime.tv_nsec; }
static s64 _get_current_time_sec(void) { s64 msecs; ktime_t now; struct timeval tv; now = ktime_get_boottime(); tv = ktime_to_timeval(now); return (s64) tv.tv_sec; }
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(ktime_get_boottime()); data->timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec; select_irq_msg(data); data->uIrqCnt++; return IRQ_HANDLED; }
static void manta_lcd_on(void) { s64 us = ktime_us_delta(lcd_on_time, ktime_get_boottime()); if (us > LCD_POWER_OFF_TIME_US) { pr_warn("lcd on sleep time too long\n"); us = LCD_POWER_OFF_TIME_US; } if (us > 0) usleep_range(us, us); gpio_set_value(GPIO_LCD_EN, 1); usleep_range(200000, 200000); }
static void xyref5260_lcd_off(void) { gpio_request_one(EXYNOS5260_GPD2(2), GPIOF_OUT_INIT_LOW, "GPD2"); gpio_free(EXYNOS5260_GPD2(2)); usleep_range(5000, 6000); #ifndef CONFIG_BACKLIGHT_PWM gpio_request_one(EXYNOS5260_GPD2(1), GPIOF_OUT_INIT_LOW, "GPD2"); usleep_range(5000, 6000); gpio_free(EXYNOS5260_GPD2(1)); #endif lcd_on_time = ktime_add_us(ktime_get_boottime(), LCD_POWER_OFF_TIME_US); }
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(ktime_get_boottime()); data->timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec; if (gpio_get_value(data->mcu_int1)) { ssp_info("MCU int HIGH"); return IRQ_HANDLED; } select_irq_msg(data); data->uIrqCnt++; return IRQ_HANDLED; }
static irqreturn_t yas_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct iio_buffer *buffer = indio_dev->buffer; struct yas_state *st = iio_priv(indio_dev); int len = 0, i, j; size_t datasize = buffer->access->get_bytes_per_datum(buffer); int32_t *mag; struct timespec ts; s64 timestamp; mag = (int32_t *) kmalloc(datasize, GFP_KERNEL); if (mag == NULL) goto done; if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) { j = 0; for (i = 0; i < 3; i++) { if (test_bit(i, indio_dev->active_scan_mask)) { mag[j] = st->compass_data[i]; j++; } } len = j * 4; } /* Guaranteed to be aligned with 8 byte boundary */ //if (indio_dev->scan_timestamp) // *(s64 *)((u8 *)mag + ALIGN(len, sizeof(s64))) = pf->timestamp; ts = ktime_to_timespec(ktime_get_boottime()); timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec; *(s64 *)((u8 *)mag + ALIGN(len, sizeof(s64))) = timestamp; if (timestamp <= 0) pr_err("[%s] invalid time = %lld\n", __func__, timestamp); iio_push_to_buffer(indio_dev->buffer, (u8 *)mag, 0); kfree(mag); done: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; }
static int instinctq_battery_probe(struct platform_device *pdev) { struct s3c_adc_client *client; struct instinctq_battery_pdata *pdata = pdev->dev.platform_data; struct instinctq_battery *bat; int ret, i, irq; /* Platform data is required */ if (!pdata) { dev_err(&pdev->dev, "no platform data supplied\n"); return -ENODEV; } /* Check GPIOs */ if (!gpio_is_valid(pdata->gpio_pok)) { dev_err(&pdev->dev, "Invalid gpio pin for POK line\n"); return -EINVAL; } if (!gpio_is_valid(pdata->gpio_chg)) { dev_err(&pdev->dev, "Invalid gpio pin for CHG line\n"); return -EINVAL; } if (!gpio_is_valid(pdata->gpio_en)) { dev_err(&pdev->dev, "Invalid gpio pin for EN line\n"); return -EINVAL; } if (!pdata->supply_detect_init) { dev_err(&pdev->dev, "Supply detection is required\n"); return -EINVAL; } /* Register ADC client */ client = s3c_adc_register(pdev, NULL, NULL, 0); if (IS_ERR(client)) { dev_err(&pdev->dev, "could not register adc\n"); return PTR_ERR(client); } /* Allocate driver data */ bat = kzalloc(sizeof(struct instinctq_battery), GFP_KERNEL); if (!bat) { dev_err(&pdev->dev, "could not allocate driver data\n"); ret = -ENOMEM; goto err_free_adc; } /* Claim and setup GPIOs */ ret = gpio_request(pdata->gpio_pok, dev_name(&pdev->dev)); if (ret) { dev_err(&pdev->dev, "Failed to request POK pin: %d\n", ret); goto err_free; } ret = gpio_direction_input(pdata->gpio_pok); if (ret) { dev_err(&pdev->dev, "Failed to set POK to input: %d\n", ret); goto err_gpio_pok_free; } ret = gpio_request(pdata->gpio_chg, dev_name(&pdev->dev)); if (ret) { dev_err(&pdev->dev, "Failed to request CHG pin: %d\n", ret); goto err_gpio_pok_free; } ret = gpio_direction_input(pdata->gpio_chg); if (ret) { dev_err(&pdev->dev, "Failed to set CHG to input: %d\n", ret); goto err_gpio_chg_free; } ret = gpio_request(pdata->gpio_en, dev_name(&pdev->dev)); if (ret) { dev_err(&pdev->dev, "Failed to request EN pin: %d\n", ret); goto err_gpio_chg_free; } ret = gpio_direction_output(pdata->gpio_en, pdata->gpio_en_inverted); if (ret) { dev_err(&pdev->dev, "Failed to set EN to output: %d\n", ret); goto err_gpio_en_free; } platform_set_drvdata(pdev, bat); bat->dev = &pdev->dev; bat->client = client; bat->pdata = pdata; bat->status = POWER_SUPPLY_STATUS_DISCHARGING; bat->health = POWER_SUPPLY_HEALTH_GOOD; bat->supply = instinctq_BATTERY_NONE; bat->interval = BAT_POLL_INTERVAL; bat->calibration = pdata->calibration; ret = create_lookup_table(pdata->percent_lut, pdata->percent_lut_cnt, &bat->percent_lookup); if (ret) { dev_err(&pdev->dev, "could not get create percentage lookup table"); goto err_gpio_en_free; } ret = create_lookup_table(pdata->volt_lut, pdata->volt_lut_cnt, &bat->volt_lookup); if (ret) { dev_err(&pdev->dev, "could not get create voltage lookup table"); goto err_percent_free; } ret = create_lookup_table(pdata->temp_lut, pdata->temp_lut_cnt, &bat->temp_lookup); if (ret) { dev_err(&pdev->dev, "could not get create temperature lookup table"); goto err_volt_free; } INIT_WORK(&bat->work, instinctq_battery_work); INIT_DELAYED_WORK(&bat->poll_work, instinctq_battery_poll); mutex_init(&bat->mutex); #ifdef CONFIG_HAS_WAKELOCK wake_lock_init(&bat->wakelock, WAKE_LOCK_SUSPEND, "battery"); wake_lock_init(&bat->chg_wakelock, WAKE_LOCK_SUSPEND, "charger"); wake_lock_init(&bat->fault_wakelock, WAKE_LOCK_SUSPEND, "battery fault"); wake_lock_init(&bat->suspend_lock, WAKE_LOCK_SUSPEND, "suspend_lock"); #endif #ifdef CONFIG_RTC_INTF_ALARM alarm_init(&bat->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, instinctq_battery_alarm); #endif /* Get some initial data for averaging */ for (i = 0; i < NUM_SAMPLES; ++i) { int sample; /* Get a voltage sample from the ADC */ sample = instinctq_battery_adc_read(bat->client, bat->pdata->volt_channel); if (sample < 0) { dev_warn(&pdev->dev, "Failed to get ADC sample.\n"); continue; } sample += bat->compensation; bat->vol_adc = sample; /* Put the sample and get the new average */ bat->volt_value = put_sample_get_avg(&bat->volt_avg, sample); /* Get a temperature sample from the ADC */ sample = instinctq_battery_adc_read(bat->client, bat->pdata->temp_channel); if (sample < 0) { dev_warn(&pdev->dev, "Failed to get ADC sample.\n"); continue; } bat->temp_adc = sample; /* Put the sample and get the new average */ bat->temp_value = put_sample_get_avg(&bat->temp_avg, sample); } bat->percent_value = lookup_value(&bat->percent_lookup, bat->volt_value); bat->volt_value = lookup_value(&bat->volt_lookup, bat->volt_value); bat->temp_value = lookup_value(&bat->temp_lookup, bat->temp_value); bat->last_sample = ktime_get_boottime(); /* Register the power supplies */ for (i = 0; i < instinctq_BATTERY_NUM; ++i) { bat->psy[i] = instinctq_chg_templates[i]; ret = power_supply_register(&pdev->dev, &bat->psy[i]); if (ret < 0) { dev_err(&pdev->dev, "Failed to register power supply %s (%d)\n", bat->psy[i].name, ret); break; } } /* Undo the loop on error */ if (i-- != instinctq_BATTERY_NUM) { for (; i >= 0; --i) power_supply_unregister(&bat->psy[i]); goto err_temp_free; } #ifdef CONFIG_HAS_WAKELOCK ret = device_create_file(bat->psy[instinctq_BATTERY_AC].dev, &dev_attr_suspend_lock); if (ret < 0) { dev_err(&pdev->dev, "Failed to register device attribute.\n"); goto err_psy_unreg; } #endif /* Register the battery */ bat->bat = instinctq_bat_template; ret = power_supply_register(&pdev->dev, &bat->bat); if (ret < 0) { dev_err(&pdev->dev, "Failed to register battery power supply: %d\n", ret); goto err_attr_unreg; } for (i = 0; i < ARRAY_SIZE(battery_attrs); ++i) { ret = device_create_file(bat->bat.dev, battery_attrs[i]); if (ret < 0) break; } if (ret < 0) { for (; i >= 0; --i) device_remove_file(bat->bat.dev, battery_attrs[i]); goto err_bat_unreg; } bat->workqueue = create_freezable_workqueue(dev_name(&pdev->dev)); if (!bat->workqueue) { dev_err(&pdev->dev, "Failed to create freezeable workqueue\n"); ret = -ENOMEM; goto err_remove_bat_attr; } /* Claim IRQs */ irq = gpio_to_irq(pdata->gpio_pok); if (irq <= 0) { dev_err(&pdev->dev, "POK irq invalid.\n"); goto err_destroy_workqueue; } bat->irq_pok = irq; ret = request_irq(irq, instinctq_charger_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), bat); if (ret) { dev_err(&pdev->dev, "Failed to request POK irq (%d)\n", ret); goto err_destroy_workqueue; } ret = request_irq(IRQ_BATF, instinctq_battery_fault_irq, 0, dev_name(&pdev->dev), bat); if (ret) { dev_err(&pdev->dev, "Failed to request battery fault irq (%d)\n", ret); goto err_pok_irq_free; } enable_irq_wake(bat->irq_pok); instinctq_battery_set_fault_enable(1); /* Finish */ dev_info(&pdev->dev, "successfully loaded\n"); device_init_wakeup(&pdev->dev, 1); pdata->supply_detect_init(instinctq_battery_supply_notify); /* Schedule work to check current status */ #ifdef CONFIG_HAS_WAKELOCK wake_lock(&bat->wakelock); #endif queue_work(bat->workqueue, &bat->work); return 0; err_pok_irq_free: free_irq(bat->irq_pok, bat); err_destroy_workqueue: destroy_workqueue(bat->workqueue); err_remove_bat_attr: for (i = 0; i < ARRAY_SIZE(battery_attrs); ++i) device_remove_file(bat->bat.dev, battery_attrs[i]); err_bat_unreg: power_supply_unregister(&bat->bat); err_attr_unreg: #ifdef CONFIG_HAS_WAKELOCK device_remove_file(bat->psy[instinctq_BATTERY_AC].dev, &dev_attr_suspend_lock); err_psy_unreg: #endif for (i = 0; i < instinctq_BATTERY_NUM; ++i) power_supply_unregister(&bat->psy[i]); err_temp_free: #ifdef CONFIG_HAS_WAKELOCK wake_lock_destroy(&bat->wakelock); wake_lock_destroy(&bat->chg_wakelock); wake_lock_destroy(&bat->fault_wakelock); wake_lock_destroy(&bat->suspend_lock); #endif kfree(bat->temp_lookup.table); err_volt_free: kfree(bat->volt_lookup.table); err_percent_free: kfree(bat->percent_lookup.table); err_gpio_en_free: gpio_free(pdata->gpio_en); err_gpio_chg_free: gpio_free(pdata->gpio_chg); err_gpio_pok_free: gpio_free(pdata->gpio_pok); err_free: kfree(bat); err_free_adc: s3c_adc_release(client); return ret; }
static void instinctq_battery_work(struct work_struct *work) { struct instinctq_battery *bat = container_of(work, struct instinctq_battery, work); struct instinctq_battery_pdata *pdata = bat->pdata; int is_plugged, is_healthy, chg_enable; enum instinctq_battery_supply type; int i; ktime_t now, diff; /* Cancel any pending works */ cancel_delayed_work_sync(&bat->poll_work); /* Check for external power supply connection */ is_plugged = gpio_get_value(pdata->gpio_pok) ^ pdata->gpio_pok_inverted; /* We're going to access shared data */ mutex_lock(&bat->mutex); type = bat->supply; if (type == instinctq_BATTERY_NONE) is_plugged = 0; for (i = 0; i < instinctq_BATTERY_NUM; ++i) bat->online[i] = (type == i); is_healthy = (bat->health == POWER_SUPPLY_HEALTH_GOOD); if (!is_healthy) { if (bat->health == POWER_SUPPLY_HEALTH_OVERHEAT) dev_warn(bat->dev, "Battery overheated, disabling charger.\n"); if (bat->health == POWER_SUPPLY_HEALTH_COLD); dev_warn(bat->dev, "Battery temperature too low, disabling charger.\n"); } /* Update charging status and polling interval */ chg_enable = is_plugged && is_healthy; if (bat->chg_enable == chg_enable) goto no_change; if (chg_enable) { bat->status = POWER_SUPPLY_STATUS_CHARGING; #ifdef CONFIG_HAS_WAKELOCK wake_lock(&bat->chg_wakelock); #endif /* Enable the charger */ gpio_set_value(pdata->gpio_en, !pdata->gpio_en_inverted); bat->fault = 0; #ifdef CONFIG_HAS_WAKELOCK wake_unlock(&bat->fault_wakelock); #endif } else { bat->status = POWER_SUPPLY_STATUS_DISCHARGING; /* Disable the charger */ gpio_set_value(pdata->gpio_en, pdata->gpio_en_inverted); /* Enable battery fault interrupt */ instinctq_battery_set_fault_enable(1); #ifdef CONFIG_HAS_WAKELOCK wake_lock_timeout(&bat->chg_wakelock, HZ / 2); #endif } bat->chg_enable = chg_enable; no_change: /* We're no longer accessing shared data */ mutex_unlock(&bat->mutex); /* Update the values and spin the polling loop */ now = ktime_get_boottime(); diff = ktime_sub(now, bat->last_sample); if (ktime_to_ms(diff) > bat->interval) instinctq_battery_poll(&bat->poll_work.work); else queue_delayed_work(bat->workqueue, &bat->poll_work, msecs_to_jiffies(bat->interval)); /* Notify anyone interested */ power_supply_changed(&bat->bat); for (i = 0; i < instinctq_BATTERY_NUM; ++i) power_supply_changed(&bat->psy[i]); #ifdef CONFIG_HAS_WAKELOCK wake_unlock(&bat->wakelock); #endif }
static void instinctq_battery_poll(struct work_struct *work) { struct delayed_work *dwrk = to_delayed_work(work); struct instinctq_battery *bat = container_of(dwrk, struct instinctq_battery, poll_work); struct instinctq_battery_pdata *pdata = bat->pdata; int volt_sample, volt_value, temp_sample, temp_value, percent_value; int health, update = 0; mutex_lock(&bat->mutex); /* Get a voltage sample from the ADC */ volt_sample = instinctq_battery_adc_read(bat->client, bat->pdata->volt_channel); if (volt_sample < 0) { dev_warn(bat->dev, "Failed to get ADC sample.\n"); bat->health = POWER_SUPPLY_HEALTH_UNKNOWN; goto error; } volt_sample += bat->compensation; bat->vol_adc = volt_sample; volt_sample = put_sample_get_avg(&bat->volt_avg, volt_sample); volt_value = lookup_value(&bat->volt_lookup, volt_sample); percent_value = lookup_value(&bat->percent_lookup, volt_sample); /* Get a temperature sample from the ADC */ temp_sample = instinctq_battery_adc_read(bat->client, bat->pdata->temp_channel); if (temp_sample < 0) { dev_warn(bat->dev, "Failed to get ADC sample.\n"); bat->health = POWER_SUPPLY_HEALTH_UNKNOWN; goto error; } bat->temp_adc = temp_sample; temp_sample = put_sample_get_avg(&bat->temp_avg, temp_sample); temp_value = lookup_value(&bat->temp_lookup, temp_sample); if (bat->health == POWER_SUPPLY_HEALTH_UNKNOWN) bat->health = POWER_SUPPLY_HEALTH_GOOD; bat->volt_value = volt_value; if (bat->percent_value >= percent_value || bat->status != POWER_SUPPLY_STATUS_DISCHARGING) bat->percent_value = percent_value; bat->temp_value = temp_value; bat->last_sample = ktime_get_boottime(); health = bat->health; if (temp_value <= pdata->low_temp_enter) health = POWER_SUPPLY_HEALTH_COLD; if (temp_value >= pdata->high_temp_enter) health = POWER_SUPPLY_HEALTH_OVERHEAT; if (temp_value >= pdata->low_temp_exit && temp_value <= pdata->high_temp_exit) health = POWER_SUPPLY_HEALTH_GOOD; if (bat->health != health) { bat->health = health; update = 1; } if (bat->chg_enable) { if (gpio_get_value(pdata->gpio_chg) ^ pdata->gpio_chg_inverted) bat->status = POWER_SUPPLY_STATUS_CHARGING; else bat->status = POWER_SUPPLY_STATUS_FULL; } error: mutex_unlock(&bat->mutex); /* Schedule next poll */ if (update) { queue_work(bat->workqueue, &bat->work); } else { queue_delayed_work(bat->workqueue, &bat->poll_work, msecs_to_jiffies(bat->interval)); power_supply_changed(&bat->bat); } }
static __devinit int android_bat_probe(struct platform_device *pdev) { struct android_bat_platform_data *pdata = dev_get_platdata(&pdev->dev); struct android_bat_data *battery; int ret = 0; dev_info(&pdev->dev, "Android Battery Driver\n"); battery = kzalloc(sizeof(*battery), GFP_KERNEL); if (!battery) return -ENOMEM; battery->pdata = pdata; if (!battery->pdata) { pr_err("%s : No platform data\n", __func__); ret = -EINVAL; goto err_pdata; } battery->dev = &pdev->dev; platform_set_drvdata(pdev, battery); battery->batt_health = POWER_SUPPLY_HEALTH_GOOD; battery->psy_bat.name = "android-battery", battery->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY, battery->psy_bat.properties = android_battery_props, battery->psy_bat.num_properties = ARRAY_SIZE(android_battery_props), battery->psy_bat.get_property = android_bat_get_property, battery->psy_usb.name = "android-usb", battery->psy_usb.type = POWER_SUPPLY_TYPE_USB, battery->psy_usb.supplied_to = supply_list, battery->psy_usb.num_supplicants = ARRAY_SIZE(supply_list), battery->psy_usb.properties = android_power_props, battery->psy_usb.num_properties = ARRAY_SIZE(android_power_props), battery->psy_usb.get_property = android_usb_get_property, battery->psy_ac.name = "android-ac", battery->psy_ac.type = POWER_SUPPLY_TYPE_MAINS, battery->psy_ac.supplied_to = supply_list, battery->psy_ac.num_supplicants = ARRAY_SIZE(supply_list), battery->psy_ac.properties = android_power_props, battery->psy_ac.num_properties = ARRAY_SIZE(android_power_props), battery->psy_ac.get_property = android_ac_get_property; battery->batt_vcell = -1; battery->batt_soc = -1; wake_lock_init(&battery->monitor_wake_lock, WAKE_LOCK_SUSPEND, "android-battery-monitor"); wake_lock_init(&battery->charger_wake_lock, WAKE_LOCK_SUSPEND, "android-chargerdetect"); ret = power_supply_register(&pdev->dev, &battery->psy_bat); if (ret) { dev_err(battery->dev, "%s: failed to register psy_bat\n", __func__); goto err_psy_bat_reg; } ret = power_supply_register(&pdev->dev, &battery->psy_usb); if (ret) { dev_err(battery->dev, "%s: failed to register psy_usb\n", __func__); goto err_psy_usb_reg; } ret = power_supply_register(&pdev->dev, &battery->psy_ac); if (ret) { dev_err(battery->dev, "%s: failed to register psy_ac\n", __func__); goto err_psy_ac_reg; } battery->monitor_wqueue = alloc_workqueue(dev_name(&pdev->dev), WQ_FREEZABLE, 1); if (!battery->monitor_wqueue) { dev_err(battery->dev, "%s: fail to create workqueue\n", __func__); goto err_wq; } INIT_WORK(&battery->monitor_work, android_bat_monitor_work); INIT_WORK(&battery->charger_work, android_bat_charger_work); battery->callbacks.charge_source_changed = android_bat_charge_source_changed; battery->callbacks.battery_set_full = android_bat_set_full_status; if (battery->pdata && battery->pdata->register_callbacks) battery->pdata->register_callbacks(&battery->callbacks); /* get initial charger status */ if (battery->pdata->poll_charge_source) battery->charge_source = battery->pdata->poll_charge_source(); wake_lock(&battery->charger_wake_lock); queue_work(battery->monitor_wqueue, &battery->charger_work); wake_lock(&battery->monitor_wake_lock); battery->last_poll = ktime_get_boottime(); alarm_init(&battery->monitor_alarm, ALARM_BOOTTIME, android_bat_monitor_alarm); queue_work(battery->monitor_wqueue, &battery->monitor_work); battery->debugfs_entry = debugfs_create_file("android-power", S_IRUGO, NULL, battery, &android_power_debug_fops); if (!battery->debugfs_entry) pr_err("failed to create android-power debugfs entry\n"); return 0; err_wq: power_supply_unregister(&battery->psy_ac); err_psy_ac_reg: power_supply_unregister(&battery->psy_usb); err_psy_usb_reg: power_supply_unregister(&battery->psy_bat); err_psy_bat_reg: wake_lock_destroy(&battery->monitor_wake_lock); wake_lock_destroy(&battery->charger_wake_lock); err_pdata: kfree(battery); return ret; }
static void android_bat_monitor_work(struct work_struct *work) { struct android_bat_data *battery = container_of(work, struct android_bat_data, monitor_work); struct timespec cur_time; wake_lock(&battery->monitor_wake_lock); android_bat_update_data(battery); mutex_lock(&android_bat_state_lock); switch (battery->charging_status) { case POWER_SUPPLY_STATUS_FULL: if (battery->batt_vcell < battery->pdata->recharging_voltage && !battery->recharging) { battery->recharging = true; android_bat_enable_charging(battery, true); pr_info("battery: start recharging, v=%d\n", battery->batt_vcell/1000); } break; case POWER_SUPPLY_STATUS_DISCHARGING: break; case POWER_SUPPLY_STATUS_CHARGING: switch (battery->batt_health) { case POWER_SUPPLY_HEALTH_OVERHEAT: case POWER_SUPPLY_HEALTH_COLD: case POWER_SUPPLY_HEALTH_OVERVOLTAGE: case POWER_SUPPLY_HEALTH_DEAD: case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE: battery->charging_status = POWER_SUPPLY_STATUS_NOT_CHARGING; android_bat_enable_charging(battery, false); pr_info("battery: Not charging, health=%d\n", battery->batt_health); break; default: break; } break; case POWER_SUPPLY_STATUS_NOT_CHARGING: if (battery->batt_health == POWER_SUPPLY_HEALTH_GOOD) { pr_info("battery: battery health recovered\n"); if (battery->charge_source != CHARGE_SOURCE_NONE) { android_bat_enable_charging(battery, true); battery->charging_status = POWER_SUPPLY_STATUS_CHARGING; } else { battery->charging_status = POWER_SUPPLY_STATUS_DISCHARGING; } } break; default: pr_err("%s: Undefined battery status: %d\n", __func__, battery->charging_status); break; } android_bat_charging_timer(battery); get_monotonic_boottime(&cur_time); pr_info("battery: l=%d v=%d c=%d temp=%s%ld.%ld h=%d st=%d%s ct=%lu type=%s\n", battery->batt_soc, battery->batt_vcell/1000, battery->batt_current, battery->batt_temp < 0 ? "-" : "", abs(battery->batt_temp / 10), abs(battery->batt_temp % 10), battery->batt_health, battery->charging_status, battery->recharging ? "r" : "", battery->charging_start_time ? cur_time.tv_sec - battery->charging_start_time : 0, charge_source_str(battery->charge_source)); mutex_unlock(&android_bat_state_lock); power_supply_changed(&battery->psy_bat); battery->last_poll = ktime_get_boottime(); android_bat_monitor_set_alarm(battery, FAST_POLL); wake_unlock(&battery->monitor_wake_lock); return; }
static void manta_lcd_off(void) { gpio_set_value(GPIO_LCD_EN, 0); lcd_on_time = ktime_add_us(ktime_get_boottime(), LCD_POWER_OFF_TIME_US); }