RE: [PATCH 2/4] thermal: rcar_gen3_thermal: Add R-Car Gen3 thermal driver support
Hi Morimoto-san, Thanks for your comments. > > +int _linear_temp_converter(struct equation_coefs coef, > > + int temp_code) > > +{ > > + int temp, temp1, temp2; > > + > > + temp1 = MCELSIUS((CODETSD(temp_code) - coef.b1)) / coef.a1; > > + temp2 = MCELSIUS((CODETSD(temp_code) - coef.b2)) / coef.a2; > > + temp = (temp1 + temp2) / 2; > > + > > + return _round_temp(temp); > > +} > > You want to have "static" function here ? Sound good. Will update in v2. > > +static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) { > > + struct rcar_gen3_thermal_priv *priv = devdata; > > + int ctemp; > > + unsigned long flags; > > + > > + rcar_gen3_thermal_update_temp(priv); > > + > > + spin_lock_irqsave(>lock, flags); > > + ctemp = _linear_temp_converter(priv->coef, priv->ctemp); > > + spin_unlock_irqrestore(>lock, flags); > > using pointer on _linear_temp_converter() is reasonable ? > especially for struct equation_coefs coef I failed to see the benefit of the change. Could you elaborate the points ? e.g better memory protection, faster byte-code execution, readability, etc > > +static const struct rcar_gen3_thermal_data r8a7795_data = { > > + .thermal_init = r8a7795_thermal_init, }; > > + > > +static const struct rcar_gen3_thermal_data r8a7796_data = { > > + .thermal_init = r8a7796_thermal_init, }; > > + > > +static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { > > + { .compatible = "renesas,thermal-r8a7795", .data = _data}, > > + { .compatible = "renesas,thermal-r8a7796", .data = _data}, > > + { .compatible = "renesas,rcar-gen3-thermal", .data = _data}, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); > > We can't have general case in this case ? > "renesas,rcar-gen3-thermal" is not needed IMO. > Especially this driver doesn't need to care about back compatibility yet. OK. I see your point. Will update in V2. > > +static int rcar_gen3_thermal_probe(struct platform_device *pdev) { > > + struct rcar_gen3_thermal_priv *priv; > > + struct device *dev = >dev; > > + struct resource *res, *irq; > > + int ret = -ENODEV; > > + int idle; > > + struct device_node *tz_nd, *tmp_nd; > > + > > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > > + if (!priv) > > + return -ENOMEM; > > + > > + platform_set_drvdata(pdev, priv); > > + > > + priv->dev = dev; > > + > > + pm_runtime_enable(dev); > > + pm_runtime_get_sync(dev); > > + > > + priv->data = of_device_get_match_data(dev); > > + if (!priv->data) > > + goto error_unregister; > > + > > + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > > + priv->irq = 0; > > + if (irq) { > > + priv->irq = 1; > > + for_each_node_with_property(tz_nd, "polling-delay") { > > + tmp_nd = of_parse_phandle(tz_nd, > > + "thermal-sensors", 0); > > + if (tmp_nd && !strcmp(tmp_nd->full_name, > > + dev->of_node->full_name)) { > > + of_property_read_u32(tz_nd, "polling-delay", > > + ); > > + (idle > 0) ? (priv->irq = 0) : > > + (priv->irq = 1); > > + break; > > + } > > it is not readable for me. > > if (idle > 0) > priv->irq = 0; > break; > > is enough ? Unfortunately, it's not. The code tries to check "polling-delay" in order to select polling mode and get polling duration from DT. So, your proposal just do 1st part. > > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > + if (!res) > > + goto error_unregister; > > + > > + priv->base = devm_ioremap_resource(dev, res); > > + if (IS_ERR(priv->base)) { > > + ret = PTR_ERR(priv->base); > > + goto error_unregister; > > + } > > + > > + spin_lock_init(>lock); > > + INIT_DELAYED_WORK(>work, rcar_gen3_thermal_work); > > + > > + priv->id = of_alias_get_id(dev->of_node, "tsc"); > > Do we really need alias ? > is "tsc" good naming ? It's the abbreviation of Thermal sensor controller. The term has been described in HW manual. Therefore, I think it's 'reasonable' name. > Having this explanation on [1/4] patch document is useful. > of_alias_get_id() can return -ENODEV, but no error check ? Good point. Will fix in v2. > > + priv->zone = devm_thermal_zone_of_sensor_register(dev, 0, priv, > > + _gen3_tz_of_ops); > > + > > + if (IS_ERR(priv->zone)) { > > + dev_err(dev, "Can't register thermal zone\n"); > > + ret = PTR_ERR(priv->zone); > > + priv->zone = NULL; > > + goto error_unregister; > > + } > > It is not bad operation, but not readable. > How about to have local struct thermal_zone_device *zone, like this ? It's good point. I saw
RE: [PATCH 2/4] thermal: rcar_gen3_thermal: Add R-Car Gen3 thermal driver support
Hi Morimoto-san, Thanks for your comments. > > +int _linear_temp_converter(struct equation_coefs coef, > > + int temp_code) > > +{ > > + int temp, temp1, temp2; > > + > > + temp1 = MCELSIUS((CODETSD(temp_code) - coef.b1)) / coef.a1; > > + temp2 = MCELSIUS((CODETSD(temp_code) - coef.b2)) / coef.a2; > > + temp = (temp1 + temp2) / 2; > > + > > + return _round_temp(temp); > > +} > > You want to have "static" function here ? Sound good. Will update in v2. > > +static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) { > > + struct rcar_gen3_thermal_priv *priv = devdata; > > + int ctemp; > > + unsigned long flags; > > + > > + rcar_gen3_thermal_update_temp(priv); > > + > > + spin_lock_irqsave(>lock, flags); > > + ctemp = _linear_temp_converter(priv->coef, priv->ctemp); > > + spin_unlock_irqrestore(>lock, flags); > > using pointer on _linear_temp_converter() is reasonable ? > especially for struct equation_coefs coef I failed to see the benefit of the change. Could you elaborate the points ? e.g better memory protection, faster byte-code execution, readability, etc > > +static const struct rcar_gen3_thermal_data r8a7795_data = { > > + .thermal_init = r8a7795_thermal_init, }; > > + > > +static const struct rcar_gen3_thermal_data r8a7796_data = { > > + .thermal_init = r8a7796_thermal_init, }; > > + > > +static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { > > + { .compatible = "renesas,thermal-r8a7795", .data = _data}, > > + { .compatible = "renesas,thermal-r8a7796", .data = _data}, > > + { .compatible = "renesas,rcar-gen3-thermal", .data = _data}, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); > > We can't have general case in this case ? > "renesas,rcar-gen3-thermal" is not needed IMO. > Especially this driver doesn't need to care about back compatibility yet. OK. I see your point. Will update in V2. > > +static int rcar_gen3_thermal_probe(struct platform_device *pdev) { > > + struct rcar_gen3_thermal_priv *priv; > > + struct device *dev = >dev; > > + struct resource *res, *irq; > > + int ret = -ENODEV; > > + int idle; > > + struct device_node *tz_nd, *tmp_nd; > > + > > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > > + if (!priv) > > + return -ENOMEM; > > + > > + platform_set_drvdata(pdev, priv); > > + > > + priv->dev = dev; > > + > > + pm_runtime_enable(dev); > > + pm_runtime_get_sync(dev); > > + > > + priv->data = of_device_get_match_data(dev); > > + if (!priv->data) > > + goto error_unregister; > > + > > + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > > + priv->irq = 0; > > + if (irq) { > > + priv->irq = 1; > > + for_each_node_with_property(tz_nd, "polling-delay") { > > + tmp_nd = of_parse_phandle(tz_nd, > > + "thermal-sensors", 0); > > + if (tmp_nd && !strcmp(tmp_nd->full_name, > > + dev->of_node->full_name)) { > > + of_property_read_u32(tz_nd, "polling-delay", > > + ); > > + (idle > 0) ? (priv->irq = 0) : > > + (priv->irq = 1); > > + break; > > + } > > it is not readable for me. > > if (idle > 0) > priv->irq = 0; > break; > > is enough ? Unfortunately, it's not. The code tries to check "polling-delay" in order to select polling mode and get polling duration from DT. So, your proposal just do 1st part. > > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > + if (!res) > > + goto error_unregister; > > + > > + priv->base = devm_ioremap_resource(dev, res); > > + if (IS_ERR(priv->base)) { > > + ret = PTR_ERR(priv->base); > > + goto error_unregister; > > + } > > + > > + spin_lock_init(>lock); > > + INIT_DELAYED_WORK(>work, rcar_gen3_thermal_work); > > + > > + priv->id = of_alias_get_id(dev->of_node, "tsc"); > > Do we really need alias ? > is "tsc" good naming ? It's the abbreviation of Thermal sensor controller. The term has been described in HW manual. Therefore, I think it's 'reasonable' name. > Having this explanation on [1/4] patch document is useful. > of_alias_get_id() can return -ENODEV, but no error check ? Good point. Will fix in v2. > > + priv->zone = devm_thermal_zone_of_sensor_register(dev, 0, priv, > > + _gen3_tz_of_ops); > > + > > + if (IS_ERR(priv->zone)) { > > + dev_err(dev, "Can't register thermal zone\n"); > > + ret = PTR_ERR(priv->zone); > > + priv->zone = NULL; > > + goto error_unregister; > > + } > > It is not bad operation, but not readable. > How about to have local struct thermal_zone_device *zone, like this ? It's good point. I saw
Re: [PATCH 2/4] thermal: rcar_gen3_thermal: Add R-Car Gen3 thermal driver support
Hi Khiem-san Thank you for your patch > +int _linear_temp_converter(struct equation_coefs coef, > + int temp_code) > +{ > + int temp, temp1, temp2; > + > + temp1 = MCELSIUS((CODETSD(temp_code) - coef.b1)) / coef.a1; > + temp2 = MCELSIUS((CODETSD(temp_code) - coef.b2)) / coef.a2; > + temp = (temp1 + temp2) / 2; > + > + return _round_temp(temp); > +} You want to have "static" function here ? > +static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) > +{ > + struct rcar_gen3_thermal_priv *priv = devdata; > + int ctemp; > + unsigned long flags; > + > + rcar_gen3_thermal_update_temp(priv); > + > + spin_lock_irqsave(>lock, flags); > + ctemp = _linear_temp_converter(priv->coef, priv->ctemp); > + spin_unlock_irqrestore(>lock, flags); using pointer on _linear_temp_converter() is reasonable ? especially for struct equation_coefs coef > +static const struct rcar_gen3_thermal_data r8a7795_data = { > + .thermal_init = r8a7795_thermal_init, > +}; > + > +static const struct rcar_gen3_thermal_data r8a7796_data = { > + .thermal_init = r8a7796_thermal_init, > +}; > + > +static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { > + { .compatible = "renesas,thermal-r8a7795", .data = _data}, > + { .compatible = "renesas,thermal-r8a7796", .data = _data}, > + { .compatible = "renesas,rcar-gen3-thermal", .data = _data}, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); We can't have general case in this case ? "renesas,rcar-gen3-thermal" is not needed IMO. Especially this driver doesn't need to care about back compatibility yet. > +static int rcar_gen3_thermal_probe(struct platform_device *pdev) > +{ > + struct rcar_gen3_thermal_priv *priv; > + struct device *dev = >dev; > + struct resource *res, *irq; > + int ret = -ENODEV; > + int idle; > + struct device_node *tz_nd, *tmp_nd; > + > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, priv); > + > + priv->dev = dev; > + > + pm_runtime_enable(dev); > + pm_runtime_get_sync(dev); > + > + priv->data = of_device_get_match_data(dev); > + if (!priv->data) > + goto error_unregister; > + > + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > + priv->irq = 0; > + if (irq) { > + priv->irq = 1; > + for_each_node_with_property(tz_nd, "polling-delay") { > + tmp_nd = of_parse_phandle(tz_nd, > + "thermal-sensors", 0); > + if (tmp_nd && !strcmp(tmp_nd->full_name, > + dev->of_node->full_name)) { > + of_property_read_u32(tz_nd, "polling-delay", > + ); > + (idle > 0) ? (priv->irq = 0) : > + (priv->irq = 1); > + break; > + } it is not readable for me. if (idle > 0) priv->irq = 0; break; is enough ? > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) > + goto error_unregister; > + > + priv->base = devm_ioremap_resource(dev, res); > + if (IS_ERR(priv->base)) { > + ret = PTR_ERR(priv->base); > + goto error_unregister; > + } > + > + spin_lock_init(>lock); > + INIT_DELAYED_WORK(>work, rcar_gen3_thermal_work); > + > + priv->id = of_alias_get_id(dev->of_node, "tsc"); Do we really need alias ? is "tsc" good naming ? Having this explanation on [1/4] patch document is useful. of_alias_get_id() can return -ENODEV, but no error check ? > + priv->zone = devm_thermal_zone_of_sensor_register(dev, 0, priv, > + _gen3_tz_of_ops); > + > + if (IS_ERR(priv->zone)) { > + dev_err(dev, "Can't register thermal zone\n"); > + ret = PTR_ERR(priv->zone); > + priv->zone = NULL; > + goto error_unregister; > + } It is not bad operation, but not readable. How about to have local struct thermal_zone_device *zone, like this ? zone = devm_thermal_zone_of_sensor_register(); if (IS_ERR(zone)) { ... ret = PTR_ERR(zone); goto error_unregister; } priv->zone = zone; > + priv->data->thermal_init(priv); thermal_init() has return value; > + ret = _read_fuse_factor(priv); > + if (ret) > + goto error_unregister; > + _linear_coefficient_calculation(priv); > + ret = rcar_gen3_thermal_update_temp(priv); > + > + if (ret < 0) > + goto error_unregister; This is very picky comment about empty line, but this is readable for me ret = _read_fuse_factor(priv); if
Re: [PATCH 2/4] thermal: rcar_gen3_thermal: Add R-Car Gen3 thermal driver support
Hi Khiem-san Thank you for your patch > +int _linear_temp_converter(struct equation_coefs coef, > + int temp_code) > +{ > + int temp, temp1, temp2; > + > + temp1 = MCELSIUS((CODETSD(temp_code) - coef.b1)) / coef.a1; > + temp2 = MCELSIUS((CODETSD(temp_code) - coef.b2)) / coef.a2; > + temp = (temp1 + temp2) / 2; > + > + return _round_temp(temp); > +} You want to have "static" function here ? > +static int rcar_gen3_thermal_get_temp(void *devdata, int *temp) > +{ > + struct rcar_gen3_thermal_priv *priv = devdata; > + int ctemp; > + unsigned long flags; > + > + rcar_gen3_thermal_update_temp(priv); > + > + spin_lock_irqsave(>lock, flags); > + ctemp = _linear_temp_converter(priv->coef, priv->ctemp); > + spin_unlock_irqrestore(>lock, flags); using pointer on _linear_temp_converter() is reasonable ? especially for struct equation_coefs coef > +static const struct rcar_gen3_thermal_data r8a7795_data = { > + .thermal_init = r8a7795_thermal_init, > +}; > + > +static const struct rcar_gen3_thermal_data r8a7796_data = { > + .thermal_init = r8a7796_thermal_init, > +}; > + > +static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { > + { .compatible = "renesas,thermal-r8a7795", .data = _data}, > + { .compatible = "renesas,thermal-r8a7796", .data = _data}, > + { .compatible = "renesas,rcar-gen3-thermal", .data = _data}, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); We can't have general case in this case ? "renesas,rcar-gen3-thermal" is not needed IMO. Especially this driver doesn't need to care about back compatibility yet. > +static int rcar_gen3_thermal_probe(struct platform_device *pdev) > +{ > + struct rcar_gen3_thermal_priv *priv; > + struct device *dev = >dev; > + struct resource *res, *irq; > + int ret = -ENODEV; > + int idle; > + struct device_node *tz_nd, *tmp_nd; > + > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, priv); > + > + priv->dev = dev; > + > + pm_runtime_enable(dev); > + pm_runtime_get_sync(dev); > + > + priv->data = of_device_get_match_data(dev); > + if (!priv->data) > + goto error_unregister; > + > + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); > + priv->irq = 0; > + if (irq) { > + priv->irq = 1; > + for_each_node_with_property(tz_nd, "polling-delay") { > + tmp_nd = of_parse_phandle(tz_nd, > + "thermal-sensors", 0); > + if (tmp_nd && !strcmp(tmp_nd->full_name, > + dev->of_node->full_name)) { > + of_property_read_u32(tz_nd, "polling-delay", > + ); > + (idle > 0) ? (priv->irq = 0) : > + (priv->irq = 1); > + break; > + } it is not readable for me. if (idle > 0) priv->irq = 0; break; is enough ? > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) > + goto error_unregister; > + > + priv->base = devm_ioremap_resource(dev, res); > + if (IS_ERR(priv->base)) { > + ret = PTR_ERR(priv->base); > + goto error_unregister; > + } > + > + spin_lock_init(>lock); > + INIT_DELAYED_WORK(>work, rcar_gen3_thermal_work); > + > + priv->id = of_alias_get_id(dev->of_node, "tsc"); Do we really need alias ? is "tsc" good naming ? Having this explanation on [1/4] patch document is useful. of_alias_get_id() can return -ENODEV, but no error check ? > + priv->zone = devm_thermal_zone_of_sensor_register(dev, 0, priv, > + _gen3_tz_of_ops); > + > + if (IS_ERR(priv->zone)) { > + dev_err(dev, "Can't register thermal zone\n"); > + ret = PTR_ERR(priv->zone); > + priv->zone = NULL; > + goto error_unregister; > + } It is not bad operation, but not readable. How about to have local struct thermal_zone_device *zone, like this ? zone = devm_thermal_zone_of_sensor_register(); if (IS_ERR(zone)) { ... ret = PTR_ERR(zone); goto error_unregister; } priv->zone = zone; > + priv->data->thermal_init(priv); thermal_init() has return value; > + ret = _read_fuse_factor(priv); > + if (ret) > + goto error_unregister; > + _linear_coefficient_calculation(priv); > + ret = rcar_gen3_thermal_update_temp(priv); > + > + if (ret < 0) > + goto error_unregister; This is very picky comment about empty line, but this is readable for me ret = _read_fuse_factor(priv); if
[PATCH 2/4] thermal: rcar_gen3_thermal: Add R-Car Gen3 thermal driver support
Signed-off-by: Hien DangSigned-off-by: Thao Nguyen Signed-off-by: Khiem Nguyen --- drivers/thermal/Kconfig | 9 + drivers/thermal/Makefile| 1 + drivers/thermal/rcar_gen3_thermal.c | 524 3 files changed, 534 insertions(+) create mode 100644 drivers/thermal/rcar_gen3_thermal.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 2d702ca..151feb7 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -223,6 +223,15 @@ config RCAR_THERMAL Enable this to plug the R-Car thermal sensor driver into the Linux thermal framework. +config RCAR_GEN3_THERMAL + tristate "Renesas R-Car Gen3 thermal driver" + depends on ARCH_RENESAS || COMPILE_TEST + depends on HAS_IOMEM + depends on OF + help + Enable this to plug the R-Car Gen3 thermal sensor driver into the Linux + thermal framework. + config KIRKWOOD_THERMAL tristate "Temperature sensor on Marvell Kirkwood SoCs" depends on MACH_KIRKWOOD || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index cded802..3ac9186 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM)+= qcom-spmi-temp-alarm.o obj-$(CONFIG_SPEAR_THERMAL)+= spear_thermal.o obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o +obj-$(CONFIG_RCAR_GEN3_THERMAL)+= rcar_gen3_thermal.o obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o obj-y += samsung/ obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c new file mode 100644 index 000..a9a372b --- /dev/null +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -0,0 +1,524 @@ +/* + * R-Car Gen3 THS/CIVM thermal sensor driver + * Based on drivers/thermal/rcar_thermal.c + * + * Copyright (C) 2016 Renesas Electronics Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register offset */ +#define REG_GEN3_CTSR 0x20 +#define REG_GEN3_THCTR 0x20 +#define REG_GEN3_IRQSTR0x04 +#define REG_GEN3_IRQMSK0x08 +#define REG_GEN3_IRQCTL0x0C +#define REG_GEN3_IRQEN 0x10 +#define REG_GEN3_IRQTEMP1 0x14 +#define REG_GEN3_IRQTEMP2 0x18 +#define REG_GEN3_IRQTEMP3 0x1C +#define REG_GEN3_TEMP 0x28 +#define REG_GEN3_THCODE1 0x50 +#define REG_GEN3_THCODE2 0x54 +#define REG_GEN3_THCODE3 0x58 + +#define PTAT_BASE 0xE6198000 +#define REG_GEN3_PTAT1 0x5C +#define REG_GEN3_PTAT2 0x60 +#define REG_GEN3_PTAT3 0x64 +#define PTAT_SIZE REG_GEN3_PTAT3 + +/* CTSR bit */ +#define PONM(0x1 << 8) +#define AOUT(0x1 << 7) +#define THBGR (0x1 << 5) +#define VMEN(0x1 << 4) +#define VMST(0x1 << 1) +#define THSST (0x1 << 0) + +/* THCTR bit */ +#define CTCTL (0x1 << 24) +#define THCNTSEN(x)(x << 16) + +#define BIT_LEN_12 0x1 + +#define CTEMP_MASK 0xFFF + +#define MCELSIUS(temp) ((temp) * 1000) +#define TEMP_IRQ_SHIFT(tsc_id) (0x1 << tsc_id) +#define TEMPD_IRQ_SHIFT(tsc_id)(0x1 << (tsc_id + 3)) +#define GEN3_FUSE_MASK 0xFFF + +/* Structure for thermal temperature calculation */ +struct equation_coefs { + long a1; + long b1; + long a2; + long b2; +}; + +struct fuse_factors { + int thcode_1; + int thcode_2; + int thcode_3; + int ptat_1; + int ptat_2; + int ptat_3; +}; + +struct rcar_gen3_thermal_priv { + void __iomem *base; + struct device *dev; + struct thermal_zone_device *zone; + struct delayed_work work; + struct fuse_factors factor; + struct equation_coefs coef; + spinlock_t lock; + int id; + int irq; + u32 ctemp; + const struct rcar_gen3_thermal_data *data; +}; + +struct rcar_gen3_thermal_data { + int (*thermal_init)(struct rcar_gen3_thermal_priv *priv); +}; + +#define rcar_priv_to_dev(priv) ((priv)->dev) +#define rcar_has_irq_support(priv) ((priv)->irq) + +/* Temperature calculation
[PATCH 2/4] thermal: rcar_gen3_thermal: Add R-Car Gen3 thermal driver support
Signed-off-by: Hien Dang Signed-off-by: Thao Nguyen Signed-off-by: Khiem Nguyen --- drivers/thermal/Kconfig | 9 + drivers/thermal/Makefile| 1 + drivers/thermal/rcar_gen3_thermal.c | 524 3 files changed, 534 insertions(+) create mode 100644 drivers/thermal/rcar_gen3_thermal.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 2d702ca..151feb7 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -223,6 +223,15 @@ config RCAR_THERMAL Enable this to plug the R-Car thermal sensor driver into the Linux thermal framework. +config RCAR_GEN3_THERMAL + tristate "Renesas R-Car Gen3 thermal driver" + depends on ARCH_RENESAS || COMPILE_TEST + depends on HAS_IOMEM + depends on OF + help + Enable this to plug the R-Car Gen3 thermal sensor driver into the Linux + thermal framework. + config KIRKWOOD_THERMAL tristate "Temperature sensor on Marvell Kirkwood SoCs" depends on MACH_KIRKWOOD || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index cded802..3ac9186 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM)+= qcom-spmi-temp-alarm.o obj-$(CONFIG_SPEAR_THERMAL)+= spear_thermal.o obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o +obj-$(CONFIG_RCAR_GEN3_THERMAL)+= rcar_gen3_thermal.o obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o obj-y += samsung/ obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c new file mode 100644 index 000..a9a372b --- /dev/null +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -0,0 +1,524 @@ +/* + * R-Car Gen3 THS/CIVM thermal sensor driver + * Based on drivers/thermal/rcar_thermal.c + * + * Copyright (C) 2016 Renesas Electronics Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register offset */ +#define REG_GEN3_CTSR 0x20 +#define REG_GEN3_THCTR 0x20 +#define REG_GEN3_IRQSTR0x04 +#define REG_GEN3_IRQMSK0x08 +#define REG_GEN3_IRQCTL0x0C +#define REG_GEN3_IRQEN 0x10 +#define REG_GEN3_IRQTEMP1 0x14 +#define REG_GEN3_IRQTEMP2 0x18 +#define REG_GEN3_IRQTEMP3 0x1C +#define REG_GEN3_TEMP 0x28 +#define REG_GEN3_THCODE1 0x50 +#define REG_GEN3_THCODE2 0x54 +#define REG_GEN3_THCODE3 0x58 + +#define PTAT_BASE 0xE6198000 +#define REG_GEN3_PTAT1 0x5C +#define REG_GEN3_PTAT2 0x60 +#define REG_GEN3_PTAT3 0x64 +#define PTAT_SIZE REG_GEN3_PTAT3 + +/* CTSR bit */ +#define PONM(0x1 << 8) +#define AOUT(0x1 << 7) +#define THBGR (0x1 << 5) +#define VMEN(0x1 << 4) +#define VMST(0x1 << 1) +#define THSST (0x1 << 0) + +/* THCTR bit */ +#define CTCTL (0x1 << 24) +#define THCNTSEN(x)(x << 16) + +#define BIT_LEN_12 0x1 + +#define CTEMP_MASK 0xFFF + +#define MCELSIUS(temp) ((temp) * 1000) +#define TEMP_IRQ_SHIFT(tsc_id) (0x1 << tsc_id) +#define TEMPD_IRQ_SHIFT(tsc_id)(0x1 << (tsc_id + 3)) +#define GEN3_FUSE_MASK 0xFFF + +/* Structure for thermal temperature calculation */ +struct equation_coefs { + long a1; + long b1; + long a2; + long b2; +}; + +struct fuse_factors { + int thcode_1; + int thcode_2; + int thcode_3; + int ptat_1; + int ptat_2; + int ptat_3; +}; + +struct rcar_gen3_thermal_priv { + void __iomem *base; + struct device *dev; + struct thermal_zone_device *zone; + struct delayed_work work; + struct fuse_factors factor; + struct equation_coefs coef; + spinlock_t lock; + int id; + int irq; + u32 ctemp; + const struct rcar_gen3_thermal_data *data; +}; + +struct rcar_gen3_thermal_data { + int (*thermal_init)(struct rcar_gen3_thermal_priv *priv); +}; + +#define rcar_priv_to_dev(priv) ((priv)->dev) +#define rcar_has_irq_support(priv) ((priv)->irq) + +/* Temperature calculation */ +#define CODETSD(x) ((x) * 1000) +#define TJ_1 96000L +#define TJ_3 (-41000L)