--- /dev/null
+#include <errno.h>
+#include <limits.h>
+#include <pass/hal.h>
+#include <pass/hal-log.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../shared/sysfs.h"
+
+/* TODO: Version! */
+#define HAL_VERSION MAKE_2B_CODE_4(VER_MAJOR,VER_MINOR,VER_REVISION,VER_RELEASE)
+#define DEV_VERSION_CPU MAKE_2B_CODE_2(1,0)
+
+#define CPUFREQ_PATH_PREFIX "/sys/devices/system/cpu/"
+#define CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX "/cpufreq/scaling_governor"
+#define CPUFREQ_AVAIL_GOVERNOR_PATH_SUFFIX "/cpufreq/scaling_available_governors"
+
+/*
+ * The cpuinfo_cur_freq indicates the actual operating CPU freqeuncy
+ * and scaling_cur_freq is the CPU frequency set by the CPUFREQ policy.
+ */
+#define CPUFREQ_CURR_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_cur_freq"
+#define CPUFREQ_MIN_FREQ_PATH_SUFFIX "/cpufreq/scaling_min_freq"
+#define CPUFREQ_MAX_FREQ_PATH_SUFFIX "/cpufreq/scaling_max_freq"
+#define CPUFREQ_UP_THRESHOLD_PATH_SUFFIX "/cpufreq/ondemand/up_threshold"
+
+#define LOADTABLE_PATH_PREFIX "/sys/kernel/debug/cpufreq/"
+#define LOADTABLE_PATH_SUFFIX "/load_table"
+
+#define CPU_ONLINE_PATH_PREFIX "/sys/devices/system/cpu/cpu"
+#define CPU_ONLINE_PATH_SUFFIX "/online"
+#define CPU_ONLINE_STATE_ON 1
+#define CPU_ONLINE_STATE_OFF 0
+
+#define TMU_PATH_PREFIX "/sys/class/thermal/thermal_zone"
+#define TMU_TEMP_PATH_SUFFIX "/temp"
+#define TMU_POLICY_PATH_SUFFIX "/policy"
+
+#define TM2_CPU_MIN_NUM 0
+#define TM2_CPU_MAX_NUM 7
+
+#define TM2_CPU_LITTLE_RESNAME "cpu0"
+#define TM2_CPU_BIG_RESNAME "cpu4"
+#define TM2_CPU_LITTLE_THERMAL_ZONE_NUM 3
+#define TM2_CPU_BIG_THERMAL_ZONE_NUM 0
+
+
+static int tm2_dvfs_get_curr_governor(char *res_name, char *governor)
+{
+ char path[PATH_MAX];
+ int ret;
+
+ if ((!res_name) || (!governor))
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%s%s",
+ CPUFREQ_PATH_PREFIX,
+ res_name,
+ CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX);
+
+ ret = sysfs_read_str(path, governor, BUFF_MAX);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tm2_dvfs_set_curr_governor(char *res_name, char *governor)
+{
+ char path[PATH_MAX];
+ int ret;
+
+ if ((!res_name) || (!governor))
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%s%s",
+ CPUFREQ_PATH_PREFIX,
+ res_name,
+ CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX);
+
+ ret = sysfs_write_str(path, governor);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tm2_dvfs_get_curr_freq(char *res_name)
+{
+ char path[PATH_MAX];
+ int freq, ret;
+
+ if (!res_name)
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%s%s",
+ CPUFREQ_PATH_PREFIX,
+ res_name,
+ CPUFREQ_CURR_FREQ_PATH_SUFFIX);
+
+ ret = sysfs_read_int(path, &freq);
+ if (ret < 0)
+ return ret;
+
+ return freq;
+}
+
+static int tm2_dvfs_get_min_freq(char *res_name)
+{
+ char path[PATH_MAX];
+ int freq, ret;
+
+ if (!res_name)
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%s%s",
+ CPUFREQ_PATH_PREFIX,
+ res_name,
+ CPUFREQ_MIN_FREQ_PATH_SUFFIX);
+
+ ret = sysfs_read_int(path, &freq);
+ if (ret < 0)
+ return ret;
+
+ return freq;
+}
+
+static int tm2_dvfs_set_min_freq(char *res_name, int freq)
+{
+ char path[PATH_MAX];
+ int ret;
+
+ if ((!res_name) || (freq < 0))
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%s%s",
+ CPUFREQ_PATH_PREFIX,
+ res_name,
+ CPUFREQ_MIN_FREQ_PATH_SUFFIX);
+
+ ret = sysfs_write_int(path, freq);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tm2_dvfs_get_max_freq(char *res_name)
+{
+ char path[PATH_MAX];
+ int freq, ret;
+
+ if (!res_name)
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%s%s",
+ CPUFREQ_PATH_PREFIX,
+ res_name,
+ CPUFREQ_MAX_FREQ_PATH_SUFFIX);
+
+ ret = sysfs_read_int(path, &freq);
+ if (ret < 0)
+ return ret;
+
+ return freq;
+}
+
+static int tm2_dvfs_set_max_freq(char *res_name, int freq)
+{
+ char path[PATH_MAX];
+ int ret;
+
+ if ((!res_name) || (freq < 0))
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%s%s",
+ CPUFREQ_PATH_PREFIX,
+ res_name,
+ CPUFREQ_MAX_FREQ_PATH_SUFFIX);
+
+ ret = sysfs_write_int(path, freq);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int tm2_dvfs_get_up_threshold(char *res_name)
+{
+ char path[PATH_MAX];
+ int val, ret;
+
+ if (!res_name)
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%s%s",
+ CPUFREQ_PATH_PREFIX,
+ res_name,
+ CPUFREQ_UP_THRESHOLD_PATH_SUFFIX);
+
+ ret = sysfs_read_int(path, &val);
+ if (ret < 0)
+ return ret;
+
+ return val;
+}
+
+static int tm2_dvfs_set_up_threshold(char *res_name, int up_threshold)
+{
+ char path[PATH_MAX];
+ int ret;
+
+ if ((!res_name) || (up_threshold < 0))
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%s%s",
+ CPUFREQ_PATH_PREFIX,
+ res_name,
+ CPUFREQ_UP_THRESHOLD_PATH_SUFFIX);
+
+ ret = sysfs_write_int(path, up_threshold);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int tm2_dvfs_get_load_table(char *res_name, void *pass_cpu_load_table)
+{
+ return 0;
+}
+
+static struct pass_resource_dvfs_ops tm2_cpu_dvfs_ops = {
+ .get_curr_governor = tm2_dvfs_get_curr_governor,
+ .set_curr_governor = tm2_dvfs_set_curr_governor,
+ .get_avail_governor = NULL,
+ .get_curr_freq = tm2_dvfs_get_curr_freq,
+ .get_min_freq = tm2_dvfs_get_min_freq,
+ .set_min_freq = tm2_dvfs_set_min_freq,
+ .get_max_freq = tm2_dvfs_get_max_freq,
+ .set_max_freq = tm2_dvfs_set_max_freq,
+ .get_up_threshold = tm2_dvfs_get_up_threshold,
+ .set_up_threshold = tm2_dvfs_set_up_threshold,
+ .get_load_table = tm2_dvfs_get_load_table,
+};
+
+static int tm2_hotplug_get_online_state(char *res_name, int cpu)
+{
+ char path[PATH_MAX];
+ int ret, online;
+
+ if ((!res_name))
+ return -EINVAL;
+ if ((cpu < TM2_CPU_MIN_NUM) || (cpu > TM2_CPU_MAX_NUM))
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%d%s",
+ CPU_ONLINE_PATH_PREFIX,
+ cpu,
+ CPU_ONLINE_PATH_SUFFIX);
+
+ ret = sysfs_read_int(path, &online);
+ if (ret < 0)
+ return ret;
+
+ return online;
+}
+
+static int tm2_hotplug_set_online_state(char *res_name, int cpu, int on)
+{
+ char path[PATH_MAX];
+ int ret;
+
+
+ if ((!res_name))
+ return -EINVAL;
+ if ((cpu < TM2_CPU_MIN_NUM) || (cpu > TM2_CPU_MAX_NUM))
+ return -EINVAL;
+ if ((on != CPU_ONLINE_STATE_ON) && (on != CPU_ONLINE_STATE_OFF))
+ return -EINVAL;
+
+ /* TODO: Can we turn off CPU0? */
+
+ snprintf(path, PATH_MAX, "%s%d%s",
+ CPU_ONLINE_PATH_PREFIX,
+ cpu,
+ CPU_ONLINE_PATH_SUFFIX);
+
+ ret = sysfs_write_int(path, on);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct pass_resource_hotplug_ops tm2_cpu_hotplus_ops = {
+ .get_online_state = tm2_hotplug_get_online_state,
+ .set_online_state = tm2_hotplug_set_online_state,
+};
+
+static int tm2_tmu_get_temp(char *res_name)
+{
+ char path[PATH_MAX];
+ int tz_num, temp;
+ int ret;
+
+ if (!res_name)
+ return -EINVAL;
+
+ if (!strcmp(res_name, TM2_CPU_LITTLE_RESNAME))
+ tz_num = TM2_CPU_LITTLE_THERMAL_ZONE_NUM;
+ else if (!strcmp(res_name, TM2_CPU_BIG_RESNAME))
+ tz_num = TM2_CPU_BIG_THERMAL_ZONE_NUM;
+ else
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%d%s",
+ TMU_PATH_PREFIX,
+ tz_num,
+ TMU_TEMP_PATH_SUFFIX);
+
+ ret = sysfs_read_int(path, &temp);
+ if (ret < 0)
+ return ret;
+
+ return temp;
+}
+
+static int tm2_tmu_get_policy(char *res_name, char *policy)
+{
+ char path[PATH_MAX];
+ int ret, tz_num;
+
+ if ((!res_name) || (!policy))
+ return -EINVAL;
+
+ if (!strcmp(res_name, TM2_CPU_LITTLE_RESNAME))
+ tz_num = TM2_CPU_LITTLE_THERMAL_ZONE_NUM;
+ else if (!strcmp(res_name, TM2_CPU_BIG_RESNAME))
+ tz_num = TM2_CPU_BIG_THERMAL_ZONE_NUM;
+ else
+ return -EINVAL;
+
+ snprintf(path, PATH_MAX, "%s%d%s",
+ TMU_PATH_PREFIX,
+ tz_num,
+ TMU_POLICY_PATH_SUFFIX);
+
+ ret = sysfs_read_str(path, policy, BUFF_MAX);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct pass_resource_tmu_ops tm2_cpu_tmu_ops = {
+ .get_temp = tm2_tmu_get_temp,
+ .get_policy = tm2_tmu_get_policy,
+};
+
+static int tm2_cpu_open(struct pass_resource_info *info,
+ struct pass_resource_common **common)
+{
+ struct pass_resource_cpu *cpu_res;
+
+ if (!info)
+ return -EINVAL;
+
+ /* TODO: Possibility of a memory leak */
+ cpu_res = calloc(1, sizeof(struct pass_resource_cpu));
+ if (!cpu_res)
+ return -ENOMEM;
+
+ cpu_res->common.info = info;
+ cpu_res->dvfs = tm2_cpu_dvfs_ops;
+ cpu_res->hotplug = tm2_cpu_hotplus_ops;
+ cpu_res->tmu = tm2_cpu_tmu_ops;
+
+ *common = (struct pass_resource_common *) cpu_res;
+
+ return 0;
+}
+
+static int tm2_cpu_close(struct pass_resource_common *common)
+{
+ if (!common)
+ return -EINVAL;
+
+ free(common);
+
+ return 0;
+}
+
+HAL_MODULE_STRUCTURE = {
+ .magic = HAL_INFO_TAG,
+ .hal_version = HAL_VERSION,
+ .device_version = DEV_VERSION_CPU,
+ .id = PASS_RESOURCE_CPU_ID,
+ .name = PASS_RESOURCE_CPU_NAME,
+ .author = "Wook Song <wook16.song@samsung.com>",
+ .open = tm2_cpu_open,
+ .close = tm2_cpu_close,
+};