|
@@ -100,13 +100,13 @@
|
|
|
#define IDLE_INTERVAL 10000
|
|
|
#define MCELSIUS 1000
|
|
|
|
|
|
-#ifdef CONFIG_EXYNOS_THERMAL_EMUL
|
|
|
+#ifdef CONFIG_THERMAL_EMULATION
|
|
|
#define EXYNOS_EMUL_TIME 0x57F0
|
|
|
#define EXYNOS_EMUL_TIME_SHIFT 16
|
|
|
#define EXYNOS_EMUL_DATA_SHIFT 8
|
|
|
#define EXYNOS_EMUL_DATA_MASK 0xFF
|
|
|
#define EXYNOS_EMUL_ENABLE 0x1
|
|
|
-#endif /* CONFIG_EXYNOS_THERMAL_EMUL */
|
|
|
+#endif /* CONFIG_THERMAL_EMULATION */
|
|
|
|
|
|
/* CPU Zone information */
|
|
|
#define PANIC_ZONE 4
|
|
@@ -145,6 +145,7 @@ struct thermal_cooling_conf {
|
|
|
struct thermal_sensor_conf {
|
|
|
char name[SENSOR_NAME_LEN];
|
|
|
int (*read_temperature)(void *data);
|
|
|
+ int (*write_emul_temp)(void *drv_data, unsigned long temp);
|
|
|
struct thermal_trip_point_conf trip_data;
|
|
|
struct thermal_cooling_conf cooling_data;
|
|
|
void *private_data;
|
|
@@ -349,6 +350,23 @@ static int exynos_get_temp(struct thermal_zone_device *thermal,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* Get temperature callback functions for thermal zone */
|
|
|
+static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
|
|
|
+ unsigned long temp)
|
|
|
+{
|
|
|
+ void *data;
|
|
|
+ int ret = -EINVAL;
|
|
|
+
|
|
|
+ if (!th_zone->sensor_conf) {
|
|
|
+ pr_info("Temperature sensor not initialised\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ data = th_zone->sensor_conf->private_data;
|
|
|
+ if (th_zone->sensor_conf->write_emul_temp)
|
|
|
+ ret = th_zone->sensor_conf->write_emul_temp(data, temp);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/* Get the temperature trend */
|
|
|
static int exynos_get_trend(struct thermal_zone_device *thermal,
|
|
|
int trip, enum thermal_trend *trend)
|
|
@@ -372,6 +390,7 @@ static struct thermal_zone_device_ops const exynos_dev_ops = {
|
|
|
.bind = exynos_bind,
|
|
|
.unbind = exynos_unbind,
|
|
|
.get_temp = exynos_get_temp,
|
|
|
+ .set_emul_temp = exynos_set_emul_temp,
|
|
|
.get_trend = exynos_get_trend,
|
|
|
.get_mode = exynos_get_mode,
|
|
|
.set_mode = exynos_set_mode,
|
|
@@ -694,6 +713,47 @@ static int exynos_tmu_read(struct exynos_tmu_data *data)
|
|
|
return temp;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_THERMAL_EMULATION
|
|
|
+static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
|
|
|
+{
|
|
|
+ struct exynos_tmu_data *data = drv_data;
|
|
|
+ unsigned int reg;
|
|
|
+ int ret = -EINVAL;
|
|
|
+
|
|
|
+ if (data->soc == SOC_ARCH_EXYNOS4210)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ if (temp && temp < MCELSIUS)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ mutex_lock(&data->lock);
|
|
|
+ clk_enable(data->clk);
|
|
|
+
|
|
|
+ reg = readl(data->base + EXYNOS_EMUL_CON);
|
|
|
+
|
|
|
+ if (temp) {
|
|
|
+ temp /= MCELSIUS;
|
|
|
+
|
|
|
+ reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
|
|
|
+ (temp_to_code(data, temp)
|
|
|
+ << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
|
|
|
+ } else {
|
|
|
+ reg &= ~EXYNOS_EMUL_ENABLE;
|
|
|
+ }
|
|
|
+
|
|
|
+ writel(reg, data->base + EXYNOS_EMUL_CON);
|
|
|
+
|
|
|
+ clk_disable(data->clk);
|
|
|
+ mutex_unlock(&data->lock);
|
|
|
+ return 0;
|
|
|
+out:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#else
|
|
|
+static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
|
|
|
+ { return -EINVAL; }
|
|
|
+#endif/*CONFIG_THERMAL_EMULATION*/
|
|
|
+
|
|
|
static void exynos_tmu_work(struct work_struct *work)
|
|
|
{
|
|
|
struct exynos_tmu_data *data = container_of(work,
|
|
@@ -727,6 +787,7 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
|
|
|
static struct thermal_sensor_conf exynos_sensor_conf = {
|
|
|
.name = "exynos-therm",
|
|
|
.read_temperature = (int (*)(void *))exynos_tmu_read,
|
|
|
+ .write_emul_temp = exynos_tmu_set_emulation,
|
|
|
};
|
|
|
|
|
|
#if defined(CONFIG_CPU_EXYNOS4210)
|
|
@@ -833,93 +894,6 @@ static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
|
|
|
platform_get_device_id(pdev)->driver_data;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_EXYNOS_THERMAL_EMUL
|
|
|
-static ssize_t exynos_tmu_emulation_show(struct device *dev,
|
|
|
- struct device_attribute *attr,
|
|
|
- char *buf)
|
|
|
-{
|
|
|
- struct platform_device *pdev = container_of(dev,
|
|
|
- struct platform_device, dev);
|
|
|
- struct exynos_tmu_data *data = platform_get_drvdata(pdev);
|
|
|
- unsigned int reg;
|
|
|
- u8 temp_code;
|
|
|
- int temp = 0;
|
|
|
-
|
|
|
- if (data->soc == SOC_ARCH_EXYNOS4210)
|
|
|
- goto out;
|
|
|
-
|
|
|
- mutex_lock(&data->lock);
|
|
|
- clk_enable(data->clk);
|
|
|
- reg = readl(data->base + EXYNOS_EMUL_CON);
|
|
|
- clk_disable(data->clk);
|
|
|
- mutex_unlock(&data->lock);
|
|
|
-
|
|
|
- if (reg & EXYNOS_EMUL_ENABLE) {
|
|
|
- reg >>= EXYNOS_EMUL_DATA_SHIFT;
|
|
|
- temp_code = reg & EXYNOS_EMUL_DATA_MASK;
|
|
|
- temp = code_to_temp(data, temp_code);
|
|
|
- }
|
|
|
-out:
|
|
|
- return sprintf(buf, "%d\n", temp * MCELSIUS);
|
|
|
-}
|
|
|
-
|
|
|
-static ssize_t exynos_tmu_emulation_store(struct device *dev,
|
|
|
- struct device_attribute *attr,
|
|
|
- const char *buf, size_t count)
|
|
|
-{
|
|
|
- struct platform_device *pdev = container_of(dev,
|
|
|
- struct platform_device, dev);
|
|
|
- struct exynos_tmu_data *data = platform_get_drvdata(pdev);
|
|
|
- unsigned int reg;
|
|
|
- int temp;
|
|
|
-
|
|
|
- if (data->soc == SOC_ARCH_EXYNOS4210)
|
|
|
- goto out;
|
|
|
-
|
|
|
- if (!sscanf(buf, "%d\n", &temp) || temp < 0)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- mutex_lock(&data->lock);
|
|
|
- clk_enable(data->clk);
|
|
|
-
|
|
|
- reg = readl(data->base + EXYNOS_EMUL_CON);
|
|
|
-
|
|
|
- if (temp) {
|
|
|
- /* Both CELSIUS and MCELSIUS type are available for input */
|
|
|
- if (temp > MCELSIUS)
|
|
|
- temp /= MCELSIUS;
|
|
|
-
|
|
|
- reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
|
|
|
- (temp_to_code(data, (temp / MCELSIUS))
|
|
|
- << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
|
|
|
- } else {
|
|
|
- reg &= ~EXYNOS_EMUL_ENABLE;
|
|
|
- }
|
|
|
-
|
|
|
- writel(reg, data->base + EXYNOS_EMUL_CON);
|
|
|
-
|
|
|
- clk_disable(data->clk);
|
|
|
- mutex_unlock(&data->lock);
|
|
|
-
|
|
|
-out:
|
|
|
- return count;
|
|
|
-}
|
|
|
-
|
|
|
-static DEVICE_ATTR(emulation, 0644, exynos_tmu_emulation_show,
|
|
|
- exynos_tmu_emulation_store);
|
|
|
-static int create_emulation_sysfs(struct device *dev)
|
|
|
-{
|
|
|
- return device_create_file(dev, &dev_attr_emulation);
|
|
|
-}
|
|
|
-static void remove_emulation_sysfs(struct device *dev)
|
|
|
-{
|
|
|
- device_remove_file(dev, &dev_attr_emulation);
|
|
|
-}
|
|
|
-#else
|
|
|
-static inline int create_emulation_sysfs(struct device *dev) { return 0; }
|
|
|
-static inline void remove_emulation_sysfs(struct device *dev) {}
|
|
|
-#endif
|
|
|
-
|
|
|
static int exynos_tmu_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct exynos_tmu_data *data;
|
|
@@ -1019,10 +993,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
|
|
|
goto err_clk;
|
|
|
}
|
|
|
|
|
|
- ret = create_emulation_sysfs(&pdev->dev);
|
|
|
- if (ret)
|
|
|
- dev_err(&pdev->dev, "Failed to create emulation mode sysfs node\n");
|
|
|
-
|
|
|
return 0;
|
|
|
err_clk:
|
|
|
platform_set_drvdata(pdev, NULL);
|
|
@@ -1034,8 +1004,6 @@ static int exynos_tmu_remove(struct platform_device *pdev)
|
|
|
{
|
|
|
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
|
|
|
|
|
|
- remove_emulation_sysfs(&pdev->dev);
|
|
|
-
|
|
|
exynos_tmu_control(pdev, false);
|
|
|
|
|
|
exynos_unregister_thermal();
|