From 2dc7021f12fe46eb4a986d57df0ef2e40e34a310 Mon Sep 17 00:00:00 2001 From: David Wu Date: Fri, 6 Mar 2015 16:59:31 +0800 Subject: [PATCH] rk3368: thermal: tsadc use usermode for rk3368 Signed-off-by: David Wu --- arch/arm64/boot/dts/rk3368.dtsi | 6 + drivers/thermal/rockchip_thermal.c | 412 ++++++++++++++++++++++++----- 2 files changed, 353 insertions(+), 65 deletions(-) diff --git a/arch/arm64/boot/dts/rk3368.dtsi b/arch/arm64/boot/dts/rk3368.dtsi index 080b88737bd2..d6bf8f6e8fb0 100755 --- a/arch/arm64/boot/dts/rk3368.dtsi +++ b/arch/arm64/boot/dts/rk3368.dtsi @@ -1190,16 +1190,22 @@ status = "okay"; }; +/* thermal-zones { #include "rk3368-thermal.dtsi" }; +*/ tsadc: tsadc@ff280000 { compatible = "rockchip,rk3368-tsadc"; reg = <0x0 0xff280000 0x0 0x100>; interrupts = ; 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"; diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index b1bbebac15a8..4eb595b26ef9 100755 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -22,6 +22,12 @@ #include #include #include +#include +#include +#include +#include +#include + /** * 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; } -- 2.34.1