Message ID | 1486048086-3431-1-git-send-email-baoyou.xie@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | [v6,1/3] dt: bindings: add documentation for zx2967 family thermal sensor | expand |
Helllo Baoyou, Sorry I was not clear enough in my previous comment. Please find the explanation below: On Thu, Feb 02, 2017 at 11:08:06PM +0800, Baoyou Xie wrote: > This patch adds thermal driver for ZTE's zx2967 family. > <cut> > + > +static int zx2967_thermal_probe(struct platform_device *pdev) > +{ > + struct zx2967_thermal_priv *priv; > + struct resource *res; > + u32 buf[2]; > + int ret, i; > + > + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + priv->regs = devm_ioremap_resource(&pdev->dev, res); > + if (IS_ERR(priv->regs)) > + return PTR_ERR(priv->regs); > + > + ret = of_property_read_u32_array(pdev->dev.of_node, > + "coefficients", buf, 2); What I meant in my previous comment is that of-thermal already does the above parsing for you. Therefore, the above line is not needed. And... > + if (ret) { > + dev_err(&pdev->dev, "failed to read coefficients\n"); > + return ret; > + } > + priv->slope = (s32)buf[0]; > + priv->offset = (s32)buf[1]; > + You should also not need to have priv data for storing the slope and offset. > + priv->clk_gate = devm_clk_get(&pdev->dev, "gate"); > + if (IS_ERR(priv->clk_gate)) { > + ret = PTR_ERR(priv->clk_gate); > + dev_err(&pdev->dev, "failed to get clock gate: %d\n", ret); > + return ret; > + } > + > + ret = clk_prepare_enable(priv->clk_gate); > + if (ret) { > + dev_err(&pdev->dev, "failed to enable converter clock: %d\n", > + ret); > + return ret; > + } > + > + priv->pclk = devm_clk_get(&pdev->dev, "pclk"); > + if (IS_ERR(priv->pclk)) { > + ret = PTR_ERR(priv->pclk); > + clk_disable_unprepare(priv->clk_gate); > + dev_err(&pdev->dev, "failed to get apb clock: %d\n", ret); > + return ret; > + } > + > + ret = clk_prepare_enable(priv->pclk); > + if (ret) { > + clk_disable_unprepare(priv->clk_gate); > + dev_err(&pdev->dev, "failed to enable converter clock: %d\n", > + ret); > + return ret; > + } > + > + mutex_init(&priv->lock); > + for (i = 0; i < NUM_SENSORS; i++) { > + struct zx2967_thermal_sensor *sensor = &priv->sensors[i]; > + > + sensor->priv = priv; > + sensor->id = i; > + sensor->tzd = thermal_zone_of_sensor_register(&pdev->dev, > + i, sensor, &zx2967_of_thermal_ops); After calling the above function, if it succeeds, and you have the coefficients property in your DTS, then > + if (IS_ERR(sensor->tzd)) { > + ret = PTR_ERR(sensor->tzd); > + dev_err(&pdev->dev, "failed to register sensor %d: %d\n", > + i, ret); > + goto remove_ts; > + } Right here, you should be able to access sensor->tzd->tzp->slope and sensor->tzd->tzp->offset, if you added the entry: coefficients = <SLOPE OFFSET>; in you thermal zone in DT. I hope this clarifies. Let me know if you are able to use the parsing from of-thermal, instead of in your driver. > + } > + priv->dev = &pdev->dev; > + platform_set_drvdata(pdev, priv); > + > + return 0; > + > +remove_ts: > + clk_disable_unprepare(priv->clk_gate); > + clk_disable_unprepare(priv->pclk); > + for (i--; i >= 0; i--) > + thermal_zone_of_sensor_unregister(&pdev->dev, > + priv->sensors[i].tzd); > + > + return ret; > +} > + > +static int zx2967_thermal_exit(struct platform_device *pdev) > +{ > + struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev); > + int i; > + > + for (i = 0; i < NUM_SENSORS; i++) { > + struct zx2967_thermal_sensor *sensor = &priv->sensors[i]; > + > + thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd); > + } > + clk_disable_unprepare(priv->pclk); > + clk_disable_unprepare(priv->clk_gate); > + > + return 0; > +} > + > +static const struct of_device_id zx2967_thermal_id_table[] = { > + { .compatible = "zte,zx296718-thermal" }, > + {} > +}; > +MODULE_DEVICE_TABLE(of, zx2967_thermal_id_table); > + > +static SIMPLE_DEV_PM_OPS(zx2967_thermal_pm_ops, > + zx2967_thermal_suspend, zx2967_thermal_resume); > + > +static struct platform_driver zx2967_thermal_driver = { > + .probe = zx2967_thermal_probe, > + .remove = zx2967_thermal_exit, > + .driver = { > + .name = "zx2967_thermal", > + .of_match_table = zx2967_thermal_id_table, > + .pm = &zx2967_thermal_pm_ops, > + }, > +}; > +module_platform_driver(zx2967_thermal_driver); > + > +MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>"); > +MODULE_DESCRIPTION("ZTE zx2967 thermal driver"); > +MODULE_LICENSE("GPL v2"); > -- > 2.7.4 > -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Documentation/devicetree/bindings/thermal/zx2967-thermal.txt b/Documentation/devicetree/bindings/thermal/zx2967-thermal.txt new file mode 100644 index 0000000..00c4900 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/zx2967-thermal.txt @@ -0,0 +1,114 @@ +* ZTE zx2967 family Thermal + +Required Properties: +- compatible: should be one of the following. + * zte,zx296718-thermal +- reg: physical base address of the controller and length of memory mapped + region. +- clocks : Pairs of phandle and specifier referencing the controller's clocks. +- clock-names: "gate" for the topcrm clock. + "pclk" for the apb clock. +- coefficients: Coefficients of thermal sensor, note that those values need to + be multiplied by 1000, consists of: + slope of calibration cure. + offset of calibration cure. +- #thermal-sensor-cells: must be 0. + +Example for tempsensor: + + tempsensor: tempsensor@148a000 { + compatible = "zte,zx296718-thermal"; + reg = <0x0148a000 0x20>; + clocks = <&topcrm TEMPSENSOR_GATE>, <&audiocrm AUDIO_TS_PCLK>; + clock-names = "gate", "pclk"; + coefficients = <1951 (-922)>; + #thermal-sensor-cells = <0>; + }; + +Example for cooling device: + + cooling_dev: cooling_dev { + cluster0_cooling_dev: cluster0-cooling-dev { + #cooling-cells = <2>; + cpumask = <0xf>; + capacitance = <1500>; + }; + + cluster1_cooling_dev: cluster1-cooling-dev { + #cooling-cells = <2>; + cpumask = <0x30>; + capacitance = <2000>; + }; + }; + +Example for thermal zones: + + thermal-zones { + zx296718_thermal: zx296718_thermal { + polling-delay-passive = <500>; + polling-delay = <1000>; + sustainable-power = <6500>; + + thermal-sensors = <&tempsensor 0>; + + trips { + trip0: switch_on_temperature { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip1: desired_temperature { + temperature = <100000>; + hysteresis = <2000>; + type = "passive"; + }; + + crit: critical_temperature { + temperature = <110000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&gpu 2 5>; + }; + + map1 { + trip = <&trip0>; + cooling-device = <&cluster0_cooling_dev 1 2>; + }; + + map2 { + trip = <&trip1>; + cooling-device = <&cluster0_cooling_dev 1 2>; + }; + + map3 { + trip = <&crit>; + cooling-device = <&cluster0_cooling_dev 1 2>; + }; + + map4 { + trip = <&trip0>; + cooling-device = <&cluster1_cooling_dev 1 2>; + contribution = <9000>; + }; + + map5 { + trip = <&trip1>; + cooling-device = <&cluster1_cooling_dev 1 2>; + contribution = <4096>; + }; + + map6 { + trip = <&crit>; + cooling-device = <&cluster1_cooling_dev 1 2>; + contribution = <4096>; + }; + }; + }; + };