summaryrefslogtreecommitdiffstats
path: root/drivers/misc/therm_fan_est.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/therm_fan_est.c')
-rw-r--r--drivers/misc/therm_fan_est.c283
1 files changed, 243 insertions, 40 deletions
diff --git a/drivers/misc/therm_fan_est.c b/drivers/misc/therm_fan_est.c
index 9312a0174..73c082ee0 100644
--- a/drivers/misc/therm_fan_est.c
+++ b/drivers/misc/therm_fan_est.c
@@ -52,6 +52,10 @@ struct therm_fan_estimator {
52 int active_trip_temps[MAX_ACTIVE_STATES]; 52 int active_trip_temps[MAX_ACTIVE_STATES];
53 int active_hysteresis[MAX_ACTIVE_STATES]; 53 int active_hysteresis[MAX_ACTIVE_STATES];
54 int active_trip_temps_hyst[(MAX_ACTIVE_STATES << 1) + 1]; 54 int active_trip_temps_hyst[(MAX_ACTIVE_STATES << 1) + 1];
55 struct thermal_zone_params *tzp;
56 int num_resources;
57 int trip_length;
58 const char *name;
55}; 59};
56 60
57 61
@@ -350,73 +354,261 @@ static struct sensor_device_attribute therm_fan_est_nodes[] = {
350#endif 354#endif
351}; 355};
352 356
357
358static int fan_est_match(struct thermal_zone_device *thz, void *data)
359{
360 return (strcmp((char *)data, thz->type) == 0);
361}
362
363static int fan_est_get_temp_func(void *data, long *temp)
364{
365 struct thermal_zone_device *thz;
366
367 thz = thermal_zone_device_find(data, fan_est_match);
368
369 if (!thz || thz->ops->get_temp(thz, temp))
370 *temp = 25000;
371
372 return 0;
373}
374
375
353static int therm_fan_est_probe(struct platform_device *pdev) 376static int therm_fan_est_probe(struct platform_device *pdev)
354{ 377{
355 int i, j; 378 int i, j;
356 long temp; 379 long temp;
357 struct therm_fan_estimator *est; 380 int err = 0;
381 int of_err = 0;
382 struct therm_fan_estimator *est_data;
383 struct therm_fan_est_subdevice *subdevs;
358 struct therm_fan_est_subdevice *dev; 384 struct therm_fan_est_subdevice *dev;
359 struct therm_fan_est_data *data; 385 struct thermal_zone_params *tzp;
386 struct device_node *node = NULL;
387 struct device_node *data_node = NULL;
388 int child_count = 0;
389 struct device_node *child = NULL;
390 const char *gov_name;
391 u32 value;
392
393 pr_info("THERMAL EST start of therm_fan_est_probe.\n");
394 if (!pdev)
395 return -EINVAL;
396
397 node = pdev->dev.of_node;
398 if (!node) {
399 pr_err("THERMAL EST: dev of_node NULL\n");
400 return -EINVAL;
401 }
402
403 data_node = of_parse_phandle(node, "shared_data", 0);
404 if (!data_node) {
405 pr_err("THERMAL EST shared data node parsing failed\n");
406 return -EINVAL;
407 }
360 408
361 est = devm_kzalloc(&pdev->dev, 409 child_count = of_get_child_count(data_node);
410 of_err |= of_property_read_u32(data_node, "ndevs", &value);
411 if (of_err) {
412 pr_err("THERMAL EST: missing ndevs\n");
413 return -ENXIO;
414 }
415 if (child_count != (int)value) {
416 pr_err("THERMAL EST: ndevs count mismatch\n");
417 return -EINVAL;
418 }
419
420 est_data = devm_kzalloc(&pdev->dev,
362 sizeof(struct therm_fan_estimator), GFP_KERNEL); 421 sizeof(struct therm_fan_estimator), GFP_KERNEL);
363 if (IS_ERR_OR_NULL(est)) 422 if (IS_ERR_OR_NULL(est_data))
364 return -ENOMEM; 423 return -ENOMEM;
365 424
366 platform_set_drvdata(pdev, est); 425 est_data->ndevs = child_count;
426 pr_info("THERMAL EST: found %d subdevs\n", est_data->ndevs);
367 427
368 data = pdev->dev.platform_data; 428 of_err |= of_property_read_string(node, "name", &est_data->name);
429 if (of_err) {
430 pr_err("THERMAL EST: name is missing\n");
431 err = -ENXIO;
432 goto free_est;
433 }
434 pr_info("THERMAL EST name: %s.\n", est_data->name);
369 435
370 est->devs = data->devs; 436 of_err |= of_property_read_u32(node, "num_resources", &value);
371 est->ndevs = data->ndevs; 437 if (of_err) {
372 est->toffset = data->toffset; 438 pr_err("THERMAL EST: num_resources is missing\n");
373 est->polling_period = data->polling_period; 439 err = -ENXIO;
440 goto free_est;
441 }
442 est_data->num_resources = value;
443 pr_info("THERMAL EST num_resources: %d\n", est_data->num_resources);
444
445 of_err |= of_property_read_u32(node, "trip_length", &value);
446 if (of_err) {
447 pr_err("THERMAL EST: missing trip length\n");
448 err = -ENXIO;
449 goto free_est;
450 }
374 451
375 for (i = 0; i < MAX_ACTIVE_STATES; i++) { 452 est_data->trip_length = (int)value;
376 est->active_trip_temps[i] = data->active_trip_temps[i]; 453 subdevs = devm_kzalloc(&pdev->dev,
377 est->active_hysteresis[i] = data->active_hysteresis[i]; 454 child_count * sizeof(struct therm_fan_est_subdevice),
455 GFP_KERNEL);
456 if (IS_ERR_OR_NULL(subdevs)) {
457 err = -ENOMEM;
458 goto free_est;
378 } 459 }
379 460
380 est->active_trip_temps_hyst[0] = data->active_trip_temps[0]; 461 /* initialize subdevs */
462 j = 0;
463 for_each_child_of_node(data_node, child) {
464 pr_info("[THERMAL EST subdev %d]\n", j);
465 of_err |= of_property_read_string(child, "dev_data",
466 &subdevs[j].dev_data);
467 if (of_err) {
468 pr_err("THERMAL EST subdev[%d] dev_data missed\n", j);
469 err = -ENXIO;
470 goto free_subdevs;
471 }
472 pr_info("THERMAL EST subdev name: %s\n",
473 (char *)subdevs[j].dev_data);
381 474
382 for (i = 1; i < MAX_ACTIVE_STATES; i++) 475 subdevs[j].get_temp = &fan_est_get_temp_func;
383 fan_set_trip_temp_hyst(est, i,
384 data->active_hysteresis[i], est->active_trip_temps[i]);
385 476
386 /* initialize history */ 477 of_err |= of_property_read_u32_array(child, "coeffs",
387 for (i = 0; i < data->ndevs; i++) { 478 subdevs[j].coeffs, est_data->trip_length);
388 dev = &est->devs[i]; 479 for (i = 0; i < est_data->trip_length; i++)
480 pr_info("THERMAL EST index %d coeffs %d\n",
481 i, subdevs[j].coeffs[i]);
482 j++;
483 }
484 est_data->devs = subdevs;
389 485
390 if (dev->get_temp(dev->dev_data, &temp)) 486 of_err |= of_property_read_u32(data_node, "toffset", &value);
391 return -EINVAL; 487 if (of_err) {
488 pr_err("THERMAL EST: missing toffset\n");
489 err = -ENXIO;
490 goto free_subdevs;
491 }
492 est_data->toffset = (long)value;
493
494 of_err |= of_property_read_u32(data_node, "polling_period", &value);
495 if (of_err) {
496 pr_err("THERMAL EST: missing polling_period\n");
497 err = -ENXIO;
498 goto free_subdevs;
499 }
500 est_data->polling_period = (long)value;
501
502 of_err |= of_property_read_u32_array(node, "active_trip_temps",
503 est_data->active_trip_temps, (size_t) est_data->trip_length);
504 if (of_err) {
505 pr_err("THERMAL EST: active trip temps failed to parse.\n");
506 err = -ENXIO;
507 goto free_subdevs;
508 }
392 509
510 of_err |= of_property_read_u32_array(node, "active_hysteresis",
511 est_data->active_hysteresis, (size_t) est_data->trip_length);
512 if (of_err) {
513 pr_err("THERMAL EST: active hysteresis failed to parse.\n");
514 err = -ENXIO;
515 goto free_subdevs;
516 }
517
518 for (i = 0; i < est_data->trip_length; i++)
519 pr_info("THERMAL EST index %d: trip_temp %d, hyst %d\n",
520 i, est_data->active_trip_temps[i],
521 est_data->active_hysteresis[i]);
522
523 est_data->active_trip_temps_hyst[0] = est_data->active_trip_temps[0];
524 for (i = 1; i < MAX_ACTIVE_STATES; i++)
525 fan_set_trip_temp_hyst(est_data, i,
526 est_data->active_hysteresis[i],
527 est_data->active_trip_temps[i]);
528 for (i = 0; i < (MAX_ACTIVE_STATES << 1) + 1; i++)
529 pr_info("THERMAL EST index %d: trip_temps_hyst %d\n",
530 i, est_data->active_trip_temps_hyst[i]);
531
532 for (i = 0; i < est_data->ndevs; i++) {
533 dev = &est_data->devs[i];
534 if (dev->get_temp(dev->dev_data, &temp)) {
535 err = -EINVAL;
536 goto free_subdevs;
537 }
393 for (j = 0; j < HIST_LEN; j++) 538 for (j = 0; j < HIST_LEN; j++)
394 dev->hist[j] = temp; 539 dev->hist[j] = temp;
540 pr_info("THERMAL EST init dev[%d] temp hist to %ld\n",
541 i, temp);
395 } 542 }
396 543
397 est->workqueue = alloc_workqueue(dev_name(&pdev->dev), 544 of_err |= of_property_read_string(data_node, "cdev_type",
398 WQ_HIGHPRI | WQ_UNBOUND, 1); 545 &est_data->cdev_type);
399 if (!est->workqueue) 546 if (of_err) {
400 return -ENOMEM; 547 pr_err("THERMAL EST: cdev_type is missing\n");
548 err = -EINVAL;
549 goto free_subdevs;
550 }
551 pr_info("THERMAL EST cdev_type: %s.\n", est_data->cdev_type);
401 552
402 est->current_trip_index = 0; 553 tzp = devm_kzalloc(&pdev->dev, sizeof(struct thermal_zone_params),
554 GFP_KERNEL);
555 if (IS_ERR_OR_NULL(tzp)) {
556 err = -ENOMEM;
557 goto free_subdevs;
558 }
559 memset(tzp, 0, sizeof(struct thermal_zone_params));
560 of_err |= of_property_read_string(data_node, "tzp_governor_name",
561 &gov_name);
562 if (of_err) {
563 pr_err("THERMAL EST: governor name is missing\n");
564 err = -EINVAL;
565 goto free_tzp;
566 }
567 strcpy(tzp->governor_name, gov_name);
568 pr_info("THERMAL EST governor name: %s\n", tzp->governor_name);
569 est_data->tzp = tzp;
570 est_data->thz = thermal_zone_device_register(
571 (char *)dev_name(&pdev->dev),
572 10, 0x3FF, est_data,
573 &therm_fan_est_ops, tzp, 0, 0);
574 if (IS_ERR_OR_NULL(est_data->thz)) {
575 pr_err("THERMAL EST: thz register failed\n");
576 err = -EINVAL;
577 goto free_tzp;
578 }
579 pr_info("THERMAL EST: thz register success.\n");
403 580
404 INIT_DELAYED_WORK(&est->therm_fan_est_work, therm_fan_est_work_func); 581 /* workqueue related */
582 est_data->workqueue = alloc_workqueue(dev_name(&pdev->dev),
583 WQ_HIGHPRI | WQ_UNBOUND, 1);
584 if (!est_data->workqueue) {
585 err = -ENOMEM;
586 goto free_tzp;
587 }
588
589 est_data->current_trip_index = 0;
590 INIT_DELAYED_WORK(&est_data->therm_fan_est_work,
591 therm_fan_est_work_func);
592 queue_delayed_work(est_data->workqueue,
593 &est_data->therm_fan_est_work,
594 msecs_to_jiffies(est_data->polling_period));
405 595
406 queue_delayed_work(est->workqueue,
407 &est->therm_fan_est_work,
408 msecs_to_jiffies(est->polling_period));
409 est->cdev_type = data->cdev_type;
410 est->thz = thermal_zone_device_register((char *) dev_name(&pdev->dev),
411 10, 0x3FF, est,
412 &therm_fan_est_ops, data->tzp, 0, 0);
413 if (IS_ERR_OR_NULL(est->thz))
414 return -EINVAL;
415 for (i = 0; i < ARRAY_SIZE(therm_fan_est_nodes); i++) 596 for (i = 0; i < ARRAY_SIZE(therm_fan_est_nodes); i++)
416 device_create_file(&pdev->dev, 597 device_create_file(&pdev->dev,
417 &therm_fan_est_nodes[i].dev_attr); 598 &therm_fan_est_nodes[i].dev_attr);
418 599
419 return 0; 600 platform_set_drvdata(pdev, est_data);
601
602 pr_info("THERMAL EST: end of probe, return err: %d\n", err);
603 return err;
604
605free_tzp:
606 devm_kfree(&pdev->dev, (void *)tzp);
607free_subdevs:
608 devm_kfree(&pdev->dev, (void *)subdevs);
609free_est:
610 devm_kfree(&pdev->dev, (void *)est_data);
611 return err;
420} 612}
421 613
422static int therm_fan_est_remove(struct platform_device *pdev) 614static int therm_fan_est_remove(struct platform_device *pdev)
@@ -427,8 +619,11 @@ static int therm_fan_est_remove(struct platform_device *pdev)
427 return -EINVAL; 619 return -EINVAL;
428 620
429 cancel_delayed_work(&est->therm_fan_est_work); 621 cancel_delayed_work(&est->therm_fan_est_work);
622 destroy_workqueue(est->workqueue);
430 thermal_zone_device_unregister(est->thz); 623 thermal_zone_device_unregister(est->thz);
431 624 devm_kfree(&pdev->dev, (void *)est->tzp);
625 devm_kfree(&pdev->dev, (void *)est->devs);
626 devm_kfree(&pdev->dev, (void *)est);
432 return 0; 627 return 0;
433} 628}
434 629
@@ -463,10 +658,18 @@ static int therm_fan_est_resume(struct platform_device *pdev)
463} 658}
464#endif 659#endif
465 660
661static const struct of_device_id of_thermal_est_match[] = {
662 { .compatible = "loki-thermal-est", },
663 { .compatible = "foster-thermal-est", },
664 {},
665};
666MODULE_DEVICE_TABLE(of, of_thermal_est_match);
667
466static struct platform_driver therm_fan_est_driver = { 668static struct platform_driver therm_fan_est_driver = {
467 .driver = { 669 .driver = {
670 .name = "therm-fan-est-driver",
468 .owner = THIS_MODULE, 671 .owner = THIS_MODULE,
469 .name = "therm-fan-est", 672 .of_match_table = of_thermal_est_match,
470 }, 673 },
471 .probe = therm_fan_est_probe, 674 .probe = therm_fan_est_probe,
472 .remove = therm_fan_est_remove, 675 .remove = therm_fan_est_remove,