// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ //#define DEBUG #include #include #include #include #include #include #include #include #include #include #include char *cooldev_name[COOL_DEV_TYPE_MAX] = {"gpufreq"}; struct meson_cooldev { int cool_dev_num; struct mutex lock;/*cooling devices mutexlock*/ struct cool_dev *cool_devs; struct thermal_zone_device *tzd; }; static struct meson_cooldev *meson_gcooldev; int get_cool_dev_type(char *type) { int i; for (i = 0; i < COOL_DEV_TYPE_MAX; i++) { if (!strcmp(type, cooldev_name[i])) return i; } return COOL_DEV_TYPE_MAX; } static int register_cool_dev(struct platform_device *pdev, int index, struct device_node *child) { struct meson_cooldev *mcooldev = platform_get_drvdata(pdev); struct cool_dev *cool = &mcooldev->cool_devs[index]; struct device_node *node; int pp, coeff; const char *node_name; pr_debug("meson_cdev index: %d %s\n", index, cool->device_type); if (of_property_read_string(child, "node_name", &node_name)) { pr_err("thermal: read node_name failed\n"); return -EINVAL; } switch (get_cool_dev_type(cool->device_type)) { /* GPU is KO, just save these parameters */ case COOL_DEV_TYPE_GPU_FREQ: node = of_find_node_by_name(NULL, node_name); if (!node) { pr_err("thermal: can't find node\n"); return -EINVAL; } cool->np = node; if (of_property_read_u32(cool->np, "num_of_pp", &pp)) { pr_err("thermal: read num_of_pp failed\n"); return -EINVAL; } if (of_property_read_u32(child, "dyn_coeff", &coeff)) { pr_err("thermal: read dyn_coeff failed\n"); return -EINVAL; } save_gpu_cool_para(coeff, cool->np, pp); return 0; default: pr_err("thermal: unknown type:%s\n", cool->device_type); return -EINVAL; } } static int parse_cool_device(struct platform_device *pdev) { struct meson_cooldev *mcooldev = platform_get_drvdata(pdev); struct device_node *np = pdev->dev.of_node; int i, ret = 0; struct cool_dev *cool; struct device_node *child; const char *str; child = of_get_child_by_name(np, "cooling_devices"); if (!child) { pr_err("meson cooldev: can't found cooling_devices\n"); return -EINVAL; } mcooldev->cool_dev_num = of_get_child_count(child); i = sizeof(struct cool_dev) * mcooldev->cool_dev_num; mcooldev->cool_devs = kzalloc(i, GFP_KERNEL); if (!mcooldev->cool_devs) { pr_err("meson cooldev: alloc mem failed\n"); return -ENOMEM; } child = of_get_next_child(child, NULL); for (i = 0; i < mcooldev->cool_dev_num; i++) { cool = &mcooldev->cool_devs[i]; if (!child) break; if (of_property_read_string(child, "device_type", &str)) pr_err("thermal: read device_type failed\n"); else cool->device_type = (char *)str; ret += register_cool_dev(pdev, i, child); child = of_get_next_child(np, child); } return ret; } static int meson_cooldev_probe(struct platform_device *pdev) { struct meson_cooldev *mcooldev; pr_debug("meson_cdev probe\n"); mcooldev = devm_kzalloc(&pdev->dev, sizeof(struct meson_cooldev), GFP_KERNEL); if (!mcooldev) return -ENOMEM; platform_set_drvdata(pdev, mcooldev); mutex_init(&mcooldev->lock); if (parse_cool_device(pdev)) pr_info("meson_cdev one or more cooldev register fail\n"); /*save pdev for mali ko api*/ meson_gcooldev = platform_get_drvdata(pdev); pr_debug("meson_cdev probe done\n"); return 0; } static void meson_cooldev_remove(struct platform_device *pdev) { } static const struct of_device_id meson_cooldev_of_match[] = { { .compatible = "amlogic, meson-cooldev" }, {}, }; struct platform_driver meson_cooldev_platdrv = { .driver = { .name = "meson-cooldev", .owner = THIS_MODULE, .of_match_table = meson_cooldev_of_match, }, .probe = meson_cooldev_probe, .remove = meson_cooldev_remove, };