summaryrefslogtreecommitdiff
path: root/gxp-thermal.c
blob: 4ba743beb41fc6463bd8020f62dd639694be572e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// SPDX-License-Identifier: GPL-2.0
/*
 * Platform thermal driver for GXP.
 *
 * Copyright (C) 2021-2023 Google LLC
 */

#include <linux/acpm_dvfs.h>
#include <linux/device.h>
#include <linux/minmax.h>

#include <gcip/gcip-pm.h>
#include <gcip/gcip-thermal.h>

#include "gxp-config.h"
#include "gxp-internal.h"
#include "gxp-pm.h"
#include "gxp-thermal.h"
#if GXP_HAS_MCU
#include "gxp-kci.h"
#include "gxp-mcu.h"
#endif /* GXP_HAS_MCU */

static int gxp_thermal_get_rate(void *data, unsigned long *rate)
{
	*rate = exynos_acpm_get_rate(AUR_DVFS_DOMAIN, 0);

	return 0;
}

static int gxp_thermal_set_rate(void *data, unsigned long rate)
{
	struct gxp_dev *gxp = data;
	int ret = 0;

	dev_warn(gxp->dev, "Received thermal throttling requests %lu", rate);
	if (!gxp_is_direct_mode(gxp)) {
#if GXP_HAS_MCU
		struct gxp_mcu *mcu = gxp_mcu_of(gxp);

		ret = gxp_kci_notify_throttling(&mcu->kci, rate);
#endif /* GXP_HAS_MCU */
	} else {
		rate = max_t(unsigned long, rate,
			     aur_power_state2rate[AUR_UUD]);
		ret = gxp_pm_blk_set_rate_acpm(gxp, rate);
	}

	if (ret) {
		dev_err(gxp->dev, "error setting gxp cooling state: %d\n", ret);
		return ret;
	}

	gxp_pm_set_thermal_limit(gxp, rate);

	return 0;
}

static int gxp_thermal_control(void *data, bool enable)
{
	return -EOPNOTSUPP;
}

int gxp_thermal_init(struct gxp_dev *gxp)
{
	const struct gcip_thermal_args args = {
		.dev = gxp->dev,
		.pm = gxp->power_mgr->pm,
		.dentry = gxp->d_entry,
		.node_name = GXP_COOLING_NAME,
		.type = GXP_COOLING_NAME,
		.data = gxp,
		.get_rate = gxp_thermal_get_rate,
		.set_rate = gxp_thermal_set_rate,
		.control = gxp_thermal_control,
	};
	struct gcip_thermal *thermal;

	if (gxp->thermal)
		return -EEXIST;

	thermal = gcip_thermal_create(&args);
	if (IS_ERR(thermal))
		return PTR_ERR(thermal);

	gxp->thermal = thermal;

	return 0;
}

void gxp_thermal_exit(struct gxp_dev *gxp)
{
	gcip_thermal_destroy(gxp->thermal);
	gxp->thermal = NULL;
}