* check the return value with help of IS_ERR() helper.
*/
static struct __thermal_zone
-__init *thermal_of_build_thermal_zone(struct device_node *np)
+__init *thermal_of_build_thermal_zone(struct device_node *np, bool container)
{
struct device_node *child = NULL, *gchild;
struct __thermal_zone *tz;
return ERR_PTR(-EINVAL);
}
+ /*
+ * Make sure we are populating the right zone type in the
+ * right phase
+ */
+ if (of_property_read_bool(np, "container") ^ container) {
+ return ERR_PTR(-EAGAIN);
+ }
+
+
tz = kzalloc(sizeof(*tz), GFP_KERNEL);
if (!tz)
return ERR_PTR(-ENOMEM);
kfree(tz);
}
+static int thermal_add_subzone(struct thermal_zone_device *container,
+ struct thermal_zone_device *zone,
+ u32 capacitance)
+{
+ if (IS_ERR_OR_NULL(container) || IS_ERR_OR_NULL(zone))
+ return -EINVAL;
+
+ mutex_lock(&zone->lock);
+ zone->capacitance = capacitance;
+ mutex_unlock(&zone->lock);
+
+ mutex_lock(&container->lock);
+ list_add_tail(&zone->subzones, &container->subzones);
+ mutex_unlock(&container->lock);
+
+ return 0;
+}
+
+static int thermal_build_subzones(struct thermal_zone_device *zone,
+ struct device_node *np)
+{
+ int i = 0;
+ int ret = 0;
+
+ INIT_LIST_HEAD(&zone->subzones);
+
+ for ( ;; i++) {
+ struct thermal_zone_device *tz;
+ struct of_phandle_args zone_specs;
+ struct device_node *child;
+ u32 capacitance;
+
+ ret = of_parse_phandle_with_fixed_args(np, "subzones", 1, i,
+ &zone_specs);
+ if (ret) {
+ of_node_put(zone_specs.np);
+ break;
+ }
+
+
+ tz = thermal_zone_get_zone_by_name(zone_specs.np->name);
+ if (IS_ERR_OR_NULL(tz)) {
+ pr_warn("Parsing thermal subzone %s failed %d\n",
+ of_node_full_name(zone_specs.np), ret);
+ of_node_put(zone_specs.np);
+ continue;
+ }
+
+ if (zone_specs.args_count == 1)
+ capacitance = zone_specs.args[0];
+ else
+ capacitance = THERMAL_SUBZONE_DEFAULT_CAPACITANCE;
+
+
+ ret = thermal_add_subzone(zone, tz, capacitance);
+
+ of_node_put(zone_specs.np);
+
+ }
+
+ return ret;
+}
+
/**
* of_parse_thermal_zones - parse device tree thermal data
*
* Return: 0 on success, proper error code otherwise
*
*/
-int __init of_parse_thermal_zones(void)
+int __init of_parse_thermal_zones_containers(bool container)
{
struct device_node *np, *child;
struct __thermal_zone *tz;
struct thermal_zone_device_ops *ops;
+ int ret;
np = of_find_node_by_name(NULL, "thermal-zones");
if (!np) {
int i, mask = 0;
u32 prop;
- tz = thermal_of_build_thermal_zone(child);
+ tz = thermal_of_build_thermal_zone(child, container);
if (IS_ERR(tz)) {
- pr_err("failed to build thermal zone %s: %ld\n",
- child->name,
- PTR_ERR(tz));
+ if (tz != ERR_PTR(-EAGAIN))
+ pr_err("failed to build thermal zone %s: %ld\n",
+ child->name,
+ PTR_ERR(tz));
continue;
}
of_thermal_free_zone(tz);
/* attempting to build remaining zones still */
}
+
+ zone->container = container;
+ if (container) {
+ ret = thermal_build_subzones(zone, child);
+ }
}
+
of_node_put(np);
return 0;
return -ENOMEM;
}
+
+int __init of_parse_thermal_zones(void)
+{
+ int ret;
+
+ /* First parse normal zones, then containers */
+ ret = of_parse_thermal_zones_containers(false);
+ if (ret)
+ return ret;
+ return of_parse_thermal_zones_containers(true);
+}
+
/**
* of_thermal_destroy_zones - remove all zones parsed and allocated resources
*