rk3368: thermal: tsadc use usermode for rk3368
authorDavid Wu <wdc@rock-chips.com>
Fri, 6 Mar 2015 08:59:31 +0000 (16:59 +0800)
committerDavid Wu <wdc@rock-chips.com>
Fri, 6 Mar 2015 08:59:31 +0000 (16:59 +0800)
Signed-off-by: David Wu <wdc@rock-chips.com>
arch/arm64/boot/dts/rk3368.dtsi
drivers/thermal/rockchip_thermal.c

index 080b88737bd2cdbf8c046795f3b8b6e93b0625fa..d6bf8f6e8fb0de5ee3d00990e59a6a3baba1feb1 100755 (executable)
                status = "okay";
        };
 
+/*
        thermal-zones {
                #include "rk3368-thermal.dtsi"
        };
+*/
 
        tsadc: tsadc@ff280000 {
                compatible = "rockchip,rk3368-tsadc";
                reg = <0x0 0xff280000 0x0 0x100>;
                interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&clk_tsadc>, <&clk_gates20 0>;
+               rockchip,grf = <&grf>;
+               rockchip,cru = <&cru>;
+               rockchip,pmu = <&pmu>;
                clock-names = "tsadc", "apb_pclk";
+               clock-frequency = <32000>;
                resets = <&reset RK3368_SRST_TSADC_P>;
                reset-names = "tsadc-apb";
                pinctrl-names = "default";
index b1bbebac15a89982d9b8165430828b095d5dc5bc..4eb595b26ef9be7db8ab81b8cc6f97f4f2a04907 100755 (executable)
 #include <linux/platform_device.h>
 #include <linux/reset.h>
 #include <linux/thermal.h>
+#include <linux/timer.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
 
 /**
  * If the temperature over a period of time High,
@@ -33,6 +39,11 @@ enum tshut_mode {
        TSHUT_MODE_GPIO,
 };
 
+enum tsadc_mode {
+       TSADC_AUTO_MODE = 0,
+       TSHUT_USER_MODE,
+};
+
 /**
  * the system Temperature Sensors tshut(tshut) polarity
  * the bit 8 is tshut polarity.
@@ -58,6 +69,7 @@ struct rockchip_tsadc_chip {
        long hw_shut_temp;
        enum tshut_mode tshut_mode;
        enum tshut_polarity tshut_polarity;
+       enum tsadc_mode mode;
        int cpu_id;
        int gpu_id;
 
@@ -83,6 +95,7 @@ struct rockchip_thermal_sensor {
 
 struct rockchip_thermal_data {
        const struct rockchip_tsadc_chip *chip;
+       struct kobject *rockchip_thermal_kobj;
        struct platform_device *pdev;
        struct reset_control *reset;
 
@@ -90,6 +103,13 @@ struct rockchip_thermal_data {
 
        struct clk *clk;
        struct clk *pclk;
+       struct regmap *cru;
+       struct regmap *grf;
+       struct regmap *pmu;
+
+       int cpu_temp_adjust;
+       int gpu_temp_adjust;
+       int cpu_temp;
 
        void __iomem *regs;
 
@@ -99,6 +119,7 @@ struct rockchip_thermal_data {
 };
 
 /* TSADC V2 Sensor info define: */
+#define TSADCV2_USER_CON                       0x00
 #define TSADCV2_AUTO_CON                       0x04
 #define TSADCV2_INT_EN                         0x08
 #define TSADCV2_INT_PD                         0x0c
@@ -131,13 +152,23 @@ struct rockchip_thermal_data {
 #define TSADCV2_AUTO_PERIOD_TIME               250 /* msec */
 #define TSADCV2_AUTO_PERIOD_HT_TIME            50  /* msec */
 #define TSADCV3_AUTO_PERIOD_TIME               1500 /* msec */
-#define TSADCV3_AUTO_PERIOD_HT_TIME            1000  /* msec */
+#define TSADCV3_AUTO_PERIOD_HT_TIME            1000 /* msec */
+
+#define TSADC_CPU_GATE
+/*#define TSADC_GPU_GATE*/
+
+#define TSADC_CLK_GATE_DELAY_TIME              50/* usec */
+#define TSADC_CLK_CYCLE_TIME                   30/* usec */
+#define TSADC_USER_MODE_DELAY_TIME             200/* usec */
+
+#define TSADC_TEST
+#define TSADC_TEST_SAMPLE_TIME                 200/* msec */
 
 struct tsadc_table {
        unsigned long code;
        long temp;
 };
-
+static struct rockchip_thermal_data *s_thermal = NULL;
 static const struct tsadc_table v2_code_table[] = {
        {TSADCV2_DATA_MASK, -40000},
        {3800, -40000},
@@ -480,6 +511,7 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
        .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
        .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
        .hw_shut_temp = 125000,
+       .mode = TSADC_AUTO_MODE,
        .cpu_id = 1,
        .gpu_id = 2,
 
@@ -496,6 +528,7 @@ static const struct rockchip_tsadc_chip rk3368_tsadc_data = {
        .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
        .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
        .hw_shut_temp = 125000,
+       .mode = TSHUT_USER_MODE,
        .cpu_id = 0,
        .gpu_id = 1,
 
@@ -521,8 +554,8 @@ static const struct of_device_id of_rockchip_thermal_match[] = {
 };
 MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
 
-static void
-rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on)
+static void rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor
+       , bool on)
 {
        struct thermal_zone_device *tzd = sensor->tzd;
 
@@ -580,6 +613,14 @@ static int rockchip_configure_from_dt(struct device *dev,
                                      struct rockchip_thermal_data *thermal)
 {
        u32 shut_temp, tshut_mode, tshut_polarity;
+       u32 rate;
+
+       if(of_property_read_u32(np, "clock-frequency", &rate)) 
+       {
+               dev_err(dev, "Missing clock-frequency property in the DT.\n");
+               return -EINVAL;
+       }
+       clk_set_rate(thermal->clk, rate);
 
        if (of_property_read_u32(np, "hw-shut-temp", &shut_temp)) {
                dev_warn(dev,
@@ -668,6 +709,208 @@ static void rockchip_thermal_reset_controller(struct reset_control *reset)
        reset_control_deassert(reset);
 }
 
+static struct rockchip_thermal_data *rockchip_thermal_get_data(void)
+{
+       BUG_ON(!s_thermal);
+       return s_thermal;
+}
+
+static int rockchip_thermal_user_mode_get_temp(struct rockchip_thermal_data *thermal,
+       int chn, int voltage)
+{
+       unsigned long flags;
+       int ret;
+
+       local_irq_save(flags);
+       /* GPU_GATING*/
+#ifdef TSADC_GPU_GATE
+       /*ret = regmap_write(thermal->cru, 0x210, 0x08000800);*/
+       ret = regmap_write(thermal->cru, 0x210, 0x09d809d8);
+       if (ret)
+               printk("Couldn't write to cru\n");
+       ret = regmap_write(thermal->cru, 0x214, 0x03000300);
+       if (ret)
+               printk("Couldn't write to cru\n");
+#endif
+
+       /* CPU 24M slow mode*/
+#ifdef TSADC_CPU_GATE
+       ret = regmap_write(thermal->cru, 0xc, 0x03000000);
+       if (ret)
+               printk("Couldn't write to cru\n");
+       ret = regmap_write(thermal->cru, 0x1c, 0x03000000);
+       if (ret)
+               printk("Couldn't write to cru\n");
+#endif
+       udelay(TSADC_CLK_GATE_DELAY_TIME);
+
+#ifdef TSADC_CPU_GATE
+       /*channe 0*/
+       u32 val_cpu_pd;
+       int val_cpu, temp_cpu;
+
+       /*power up, channel 0*/
+       writel_relaxed(0x208, thermal->regs + TSADCV2_USER_CON);
+       while(1)
+       {
+               val_cpu_pd = readl_relaxed(thermal->regs + TSADCV2_INT_PD);
+               udelay(TSADC_CLK_CYCLE_TIME);
+               if ((val_cpu_pd & 0x100) == 0x100) {
+                       udelay(TSADC_USER_MODE_DELAY_TIME);
+                       /*clear eoc inter*/
+                       writel_relaxed(0x100, thermal->regs + TSADCV2_INT_PD);
+                       /*read adc data*/
+                       val_cpu = readl_relaxed(thermal->regs + TSADCV2_DATA(0));
+                       break;
+               }
+       }
+       /*power down, channel 0*/
+       writel_relaxed(0x200, thermal->regs + TSADCV2_USER_CON);
+#endif
+
+#ifdef TSADC_GPU_GATE
+       udelay(10);
+
+       /*channe 1*/
+       u32 val_gpu_pd;
+       int val_gpu, temp_gpu;
+
+       /*power up, channel */
+       writel_relaxed(0x208 | 0x1, thermal->regs + TSADCV2_USER_CON);
+       while(1)
+       {
+               val_gpu_pd = readl_relaxed(thermal->regs + TSADCV2_INT_PD);
+               udelay(TSADC_CLK_CYCLE_TIME);
+               if ((val_gpu_pd & 0x100) == 0x100) {
+                       udelay(TSADC_USER_MODE_DELAY_TIME);
+                       /*clear eoc inter*/
+                       writel_relaxed(0x100, thermal->regs + TSADCV2_INT_PD);
+                       /*read adc data*/
+                       val_gpu = readl_relaxed(thermal->regs + TSADCV2_DATA(1));
+                       break;
+               }
+       }
+       /*power down, channel */
+       writel_relaxed(0x200, thermal->regs + TSADCV2_USER_CON);
+#endif
+
+       /* CPU normal mode*/
+#ifdef TSADC_CPU_GATE
+       ret = regmap_write(thermal->cru, 0xc, 0x03000100);
+       if (ret)
+               printk("Couldn't write to cru\n");
+       ret = regmap_write(thermal->cru, 0x1c, 0x03000100);
+       if (ret)
+               printk("Couldn't write to cru\n");
+#endif
+
+       /* GPU_UNGATING*/
+#ifdef TSADC_GPU_GATE
+       ret = regmap_write(thermal->cru, 0x214, 0x03000000);
+       if (ret)
+               printk("Couldn't write to cru\n");
+
+       ret = regmap_write(thermal->cru, 0x210, 0x09d80000);
+       if (ret)
+               printk("Couldn't write to cru\n");
+#endif
+       local_irq_restore(flags);
+
+#ifdef TSADC_CPU_GATE
+       temp_cpu = rk_tsadcv3_code_to_temp((val_cpu * voltage + 500000) / 1000000) / 1000;
+       temp_cpu = temp_cpu + thermal->cpu_temp_adjust;
+       thermal->cpu_temp = temp_cpu;
+       pr_info("cpu[%d, %d], voltage: %d\n", val_cpu, temp_cpu, voltage);
+#endif
+
+       return temp_cpu;
+}
+
+int rockchip_tsadc_get_temp(int chn, int voltage)
+{
+       struct rockchip_thermal_data *thermal = rockchip_thermal_get_data();
+       long out_temp;
+
+       if (thermal->chip->mode == TSADC_AUTO_MODE)
+       {
+               thermal->chip->get_temp(chn, thermal->regs, &out_temp);
+               return (int)out_temp/1000;
+       }
+       else
+       {
+               return rockchip_thermal_user_mode_get_temp(thermal, chn, voltage);
+       }
+}
+EXPORT_SYMBOL(rockchip_tsadc_get_temp);
+
+static ssize_t rockchip_thermal_temp_adjust_test_store(struct kobject *kobj
+       , struct kobj_attribute *attr, const char *buf, size_t n)
+{
+       struct rockchip_thermal_data *thermal = rockchip_thermal_get_data();
+       int getdata;
+       char cmd;
+       const char *buftmp = buf;
+
+       sscanf(buftmp, "%c ", &cmd);
+       switch (cmd) {
+       case 'c':
+               sscanf(buftmp, "%c %d", &cmd, &getdata);
+               thermal->cpu_temp_adjust = getdata;
+               printk("get cpu_temp_adjust value = %d\n", getdata);
+
+               break;
+       case 'g':
+               sscanf(buftmp, "%c %d", &cmd, &getdata);
+               thermal->gpu_temp_adjust = getdata;
+               printk("get gpu_temp_adjust value = %d\n", getdata);
+
+               break;
+       default:
+               printk("Unknown command\n");
+               break;
+       }
+
+       return n;
+}
+
+static ssize_t rockchip_thermal_temp_adjust_test_show(struct kobject *kobj
+       , struct kobj_attribute *attr, char *buf)
+{
+       struct rockchip_thermal_data *thermal = rockchip_thermal_get_data();
+       char *str = buf;
+
+       str += sprintf(str, "rockchip_thermal: cpu:%d, gpu:%d\n"
+               , thermal->cpu_temp_adjust, thermal->gpu_temp_adjust);
+       return (str - buf);
+}
+
+static ssize_t rockchip_thermal_temp_test_show(struct kobject *kobj
+       , struct kobj_attribute *attr, char *buf)
+{
+       struct rockchip_thermal_data *thermal = rockchip_thermal_get_data();
+       char *str = buf;
+
+       str += sprintf(str, "current cpu_temp:%d\n"
+               , thermal->cpu_temp);
+       return (str - buf);
+}
+
+struct rockchip_thermal_attribute {
+       struct attribute        attr;
+       ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
+               char *buf);
+       ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
+               const char *buf, size_t n);
+};
+
+static struct rockchip_thermal_attribute rockchip_thermal_attrs[] = {
+       /*node_name     permision show_func store_func*/
+       __ATTR(temp_adjust, S_IRUGO | S_IWUSR, rockchip_thermal_temp_adjust_test_show
+               , rockchip_thermal_temp_adjust_test_store),
+       __ATTR(temp, S_IRUGO | S_IWUSR, rockchip_thermal_temp_test_show
+               , NULL),
+};
+
 static int rockchip_thermal_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -711,6 +954,24 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
                return error;
        }
 
+       thermal->cru = syscon_regmap_lookup_by_phandle(np, "rockchip,cru");
+       if (IS_ERR(thermal->cru)) {
+               dev_err(&pdev->dev, "couldn't find cru regmap\n");
+               return PTR_ERR(thermal->cru);
+       }
+
+       thermal->pmu = syscon_regmap_lookup_by_phandle(np, "rockchip,pmu");
+       if (IS_ERR(thermal->pmu)) {
+               dev_err(&pdev->dev, "couldn't find pmu regmap\n");
+               return PTR_ERR(thermal->pmu);
+       }
+
+       thermal->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+       if (IS_ERR(thermal->grf)) {
+               dev_err(&pdev->dev, "couldn't find grf regmap\n");
+               return PTR_ERR(thermal->grf);
+       }
+
        thermal->clk = devm_clk_get(&pdev->dev, "tsadc");
        if (IS_ERR(thermal->clk)) {
                error = PTR_ERR(thermal->clk);
@@ -728,8 +989,8 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
 
        error = clk_prepare_enable(thermal->clk);
        if (error) {
-               dev_err(&pdev->dev, "failed to enable converter clock: %d\n",
-                       error);
+               dev_err(&pdev->dev, "failed to enable converter clock: %d\n"
+                       error);
                return error;
        }
 
@@ -738,9 +999,8 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "failed to enable pclk: %d\n", error);
                goto err_disable_clk;
        }
-
+       
        rockchip_thermal_reset_controller(thermal->reset);
-
        error = rockchip_configure_from_dt(&pdev->dev, np, thermal);
        if (error) {
                dev_err(&pdev->dev, "failed to parse device tree data: %d\n",
@@ -748,49 +1008,66 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
                goto err_disable_pclk;
        }
 
-       thermal->chip->initialize(thermal->regs, thermal->tshut_polarity);
-
-       error = rockchip_thermal_register_sensor(pdev, thermal,
-                                                &thermal->sensors[0],
-                                                thermal->chip->cpu_id);
-       if (error) {
-               dev_err(&pdev->dev,
-                       "failed to register CPU thermal sensor: %d\n", error);
-               goto err_disable_pclk;
-       }
-
-       error = rockchip_thermal_register_sensor(pdev, thermal,
-                                                &thermal->sensors[1],
-                                                thermal->chip->gpu_id);
-       if (error) {
-               dev_err(&pdev->dev,
-                       "failed to register GPU thermal sensor: %d\n", error);
-               goto err_unregister_cpu_sensor;
+       if (thermal->chip->mode == TSADC_AUTO_MODE)
+       {
+               thermal->chip->initialize(thermal->regs, thermal->tshut_polarity);
+               error = rockchip_thermal_register_sensor(pdev, thermal,
+                                                        &thermal->sensors[0],
+                                                        thermal->chip->cpu_id);
+               if (error) {
+                       dev_err(&pdev->dev,
+                               "failed to register CPU thermal sensor: %d\n", error);
+                       goto err_disable_pclk;
+               }
+
+               error = rockchip_thermal_register_sensor(pdev, thermal,
+                                                        &thermal->sensors[1],
+                                                        thermal->chip->gpu_id);
+               if (error) {
+                       dev_err(&pdev->dev,
+                               "failed to register GPU thermal sensor: %d\n", error);
+                       goto err_unregister_cpu_sensor;
+               }
+
+               error = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                                                 &rockchip_thermal_alarm_irq_thread,
+                                                 IRQF_ONESHOT,
+                                                 "rockchip_thermal", thermal);
+               if (error) {
+                       dev_err(&pdev->dev,
+                               "failed to request tsadc irq: %d\n", error);
+                       goto err_unregister_gpu_sensor;
+               }
+
+               thermal->chip->control(thermal->regs, true);
+
+               for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+                       rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
        }
 
-       error = devm_request_threaded_irq(&pdev->dev, irq, NULL,
-                                         &rockchip_thermal_alarm_irq_thread,
-                                         IRQF_ONESHOT,
-                                         "rockchip_thermal", thermal);
-       if (error) {
-               dev_err(&pdev->dev,
-                       "failed to request tsadc irq: %d\n", error);
-               goto err_unregister_gpu_sensor;
+       thermal->rockchip_thermal_kobj = kobject_create_and_add("rockchip_thermal", NULL);
+       if (!thermal->rockchip_thermal_kobj)
+               return -ENOMEM;
+       for (i = 0; i < ARRAY_SIZE(rockchip_thermal_attrs); i++) {
+               error = sysfs_create_file(thermal->rockchip_thermal_kobj
+                       , &rockchip_thermal_attrs[i].attr);
+               if (error != 0) {
+                       printk("create index %d error\n", i);
+                       return error;
+               }
        }
 
-       thermal->chip->control(thermal->regs, true);
-
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
-               rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
-
+       s_thermal = thermal;
        platform_set_drvdata(pdev, thermal);
 
        return 0;
 
 err_unregister_gpu_sensor:
-       thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[1].tzd);
+       if (thermal->chip->mode == TSADC_AUTO_MODE)
+               thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[1].tzd);
 err_unregister_cpu_sensor:
-       thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[0].tzd);
+       if (thermal->chip->mode == TSADC_AUTO_MODE)
+               thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[0].tzd);
 err_disable_pclk:
        clk_disable_unprepare(thermal->pclk);
 err_disable_clk:
@@ -804,15 +1081,17 @@ static int rockchip_thermal_remove(struct platform_device *pdev)
        struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev);
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) {
-               struct rockchip_thermal_sensor *sensor = &thermal->sensors[i];
-
-               rockchip_thermal_toggle_sensor(sensor, false);
-               thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd);
-       }
+       if (thermal->chip->mode == TSADC_AUTO_MODE)
+       {
+               for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) {
+                       struct rockchip_thermal_sensor *sensor = &thermal->sensors[i];
 
-       thermal->chip->control(thermal->regs, false);
+                       rockchip_thermal_toggle_sensor(sensor, false);
+                       thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd);
+               }
 
+               thermal->chip->control(thermal->regs, false);
+       }
        clk_disable_unprepare(thermal->pclk);
        clk_disable_unprepare(thermal->clk);
 
@@ -825,11 +1104,13 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev)
        struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev);
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
-               rockchip_thermal_toggle_sensor(&thermal->sensors[i], false);
-
-       thermal->chip->control(thermal->regs, false);
+       if (thermal->chip->mode == TSADC_AUTO_MODE)
+       {
+               for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+                       rockchip_thermal_toggle_sensor(&thermal->sensors[i], false);
 
+               thermal->chip->control(thermal->regs, false);
+       }
        clk_disable(thermal->pclk);
        clk_disable(thermal->clk);
 
@@ -852,23 +1133,24 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev)
                return error;
 
        rockchip_thermal_reset_controller(thermal->reset);
+       if (thermal->chip->mode == TSADC_AUTO_MODE)
+       {
+               thermal->chip->initialize(thermal->regs, thermal->tshut_polarity);
 
-       thermal->chip->initialize(thermal->regs, thermal->tshut_polarity);
-
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) {
-               int id = thermal->sensors[i].id;
+               for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) {
+                       int id = thermal->sensors[i].id;
 
-               thermal->chip->set_tshut_mode(id, thermal->regs,
-                                             thermal->tshut_mode);
-               thermal->chip->set_tshut_temp(id, thermal->regs,
-                                             thermal->hw_shut_temp);
-       }
+                       thermal->chip->set_tshut_mode(id, thermal->regs,
+                                                     thermal->tshut_mode);
+                       thermal->chip->set_tshut_temp(id, thermal->regs,
+                                                     thermal->hw_shut_temp);
+               }
 
-       thermal->chip->control(thermal->regs, true);
-
-       for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
-               rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
+               thermal->chip->control(thermal->regs, true);
 
+               for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+                       rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
+       }
        return 0;
 }