static int therm_est_pm_notify(struct notifier_block *nb, unsigned long event, void *data) { struct therm_estimator *est = container_of( nb, struct therm_estimator, pm_nb); switch (event) { case PM_SUSPEND_PREPARE: cancel_delayed_work_sync(&est->therm_est_work); cancel_delayed_work_sync(&est->timer_trip_work); break; case PM_POST_SUSPEND: est->low_limit = 0; est->high_limit = 0; therm_est_init_history(est); therm_est_init_timer_trips(est); queue_delayed_work(est->workqueue, &est->therm_est_work, msecs_to_jiffies(est->polling_period)); break; } return NOTIFY_OK; }
static void therm_est_work_func(struct work_struct *work) { int i, j, index, sum = 0; long temp; struct delayed_work *dwork = container_of(work, struct delayed_work, work); struct therm_estimator *est = container_of(dwork, struct therm_estimator, therm_est_work); if ((est->ntemp == HIST_UNINIT) && therm_est_init_history(est)) { est->cur_temp = DEFAULT_TEMP; goto out; } for (i = 0; i < est->ndevs; i++) { if (therm_est_subdev_get_temp(est->devs[i].dev_data, &temp)) { index = (est->ntemp > 0) ? (est->ntemp - 1) : 0; temp = est->devs[i].hist[(index % HIST_LEN)]; } est->devs[i].hist[(est->ntemp % HIST_LEN)] = temp; } for (i = 0; i < est->ndevs; i++) { for (j = 0; j < HIST_LEN; j++) { index = (est->ntemp - j + HIST_LEN) % HIST_LEN; sum += est->devs[i].hist[index] * est->devs[i].coeffs[j]; } } est->cur_temp = sum / 100 + est->toffset; est->ntemp++; out: if (est->thz && ((est->cur_temp < est->low_limit) || (est->cur_temp >= est->high_limit))) { thermal_zone_device_update(est->thz); therm_est_update_timer_trips(est); therm_est_update_limits(est); } queue_delayed_work(est->workqueue, &est->therm_est_work, msecs_to_jiffies(est->polling_period)); }
static int __devinit therm_est_probe(struct platform_device *pdev) { int i; struct therm_estimator *est; struct therm_est_data *data; est = kzalloc(sizeof(struct therm_estimator), GFP_KERNEL); if (IS_ERR_OR_NULL(est)) return -ENOMEM; platform_set_drvdata(pdev, est); data = therm_est_get_pdata(&pdev->dev); est->devs = data->devs; est->ndevs = data->ndevs; est->toffset = data->toffset; est->polling_period = data->polling_period; est->tc1 = data->tc1; est->tc2 = data->tc2; /* initialize history */ therm_est_init_history(est); /* initialize timer trips */ est->num_timer_trips = data->num_timer_trips; est->timer_trips = data->timer_trips; therm_est_init_timer_trips(est); mutex_init(&est->timer_trip_lock); INIT_DELAYED_WORK(&est->timer_trip_work, therm_est_timer_trip_work_func); est->workqueue = alloc_workqueue(dev_name(&pdev->dev), WQ_HIGHPRI | WQ_UNBOUND | WQ_RESCUER, 1); if (!est->workqueue) goto err; INIT_DELAYED_WORK(&est->therm_est_work, therm_est_work_func); queue_delayed_work(est->workqueue, &est->therm_est_work, msecs_to_jiffies(est->polling_period)); est->num_trips = data->num_trips; est->trips = data->trips; est->tzp = data->tzp; est->thz = thermal_zone_device_register(dev_name(&pdev->dev), est->num_trips, (1 << est->num_trips) - 1, est, &therm_est_ops, est->tzp, data->passive_delay, 0); if (IS_ERR_OR_NULL(est->thz)) goto err; for (i = 0; i < ARRAY_SIZE(therm_est_nodes); i++) device_create_file(&pdev->dev, &therm_est_nodes[i].dev_attr); #ifdef CONFIG_PM est->pm_nb.notifier_call = therm_est_pm_notify, register_pm_notifier(&est->pm_nb); #endif return 0; err: cancel_delayed_work_sync(&est->therm_est_work); if (est->workqueue) destroy_workqueue(est->workqueue); kfree(est); return -EINVAL; }