|
@@ -99,6 +99,14 @@
|
|
|
#define IDLE_INTERVAL 10000
|
|
|
#define MCELSIUS 1000
|
|
|
|
|
|
+#ifdef CONFIG_EXYNOS_THERMAL_EMUL
|
|
|
+#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 */
|
|
|
+
|
|
|
/* CPU Zone information */
|
|
|
#define PANIC_ZONE 4
|
|
|
#define WARN_ZONE 3
|
|
@@ -832,6 +840,94 @@ static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
|
|
|
return (struct exynos_tmu_platform_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 __devinit exynos_tmu_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct exynos_tmu_data *data;
|
|
@@ -930,6 +1026,11 @@ static int __devinit exynos_tmu_probe(struct platform_device *pdev)
|
|
|
dev_err(&pdev->dev, "Failed to register thermal interface\n");
|
|
|
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);
|
|
@@ -941,6 +1042,8 @@ static int __devexit 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();
|