diff options
| -rw-r--r-- | drivers/thermal/rcar_gen3_thermal.c | 103 | 
1 files changed, 99 insertions, 4 deletions
| diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index fdf16aa34eb4..e49593437ede 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -190,10 +190,64 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)  	return 0;  } -static const struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = { +static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc, +					      int mcelsius) +{ +	int celsius, val; + +	celsius = DIV_ROUND_CLOSEST(mcelsius, 1000); +	if (celsius <= INT_FIXPT(tsc->tj_t)) +		val = celsius * tsc->coef.a1 + tsc->coef.b1; +	else +		val = celsius * tsc->coef.a2 + tsc->coef.b2; + +	return INT_FIXPT(val); +} + +static int rcar_gen3_thermal_set_trips(void *devdata, int low, int high) +{ +	struct rcar_gen3_thermal_tsc *tsc = devdata; +	u32 irqmsk = 0; + +	if (low != -INT_MAX) { +		irqmsk |= IRQ_TEMPD1; +		rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1, +					rcar_gen3_thermal_mcelsius_to_temp(tsc, low)); +	} + +	if (high != INT_MAX) { +		irqmsk |= IRQ_TEMP2; +		rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2, +					rcar_gen3_thermal_mcelsius_to_temp(tsc, high)); +	} + +	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, irqmsk); + +	return 0; +} + +static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {  	.get_temp	= rcar_gen3_thermal_get_temp, +	.set_trips	= rcar_gen3_thermal_set_trips,  }; +static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data) +{ +	struct rcar_gen3_thermal_priv *priv = data; +	unsigned int i; +	u32 status; + +	for (i = 0; i < priv->num_tscs; i++) { +		status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR); +		rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0); +		if (status) +			thermal_zone_device_update(priv->tscs[i]->zone, +						   THERMAL_EVENT_UNSPECIFIED); +	} + +	return IRQ_HANDLED; +} +  static const struct soc_device_attribute r8a7795es1[] = {  	{ .soc_id = "r8a7795", .revision = "ES1.*" },  	{ /* sentinel */ } @@ -210,6 +264,9 @@ static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc)  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); +	if (tsc->zone->ops->set_trips) +		rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, +					IRQ_TEMPD1 | IRQ_TEMP2);  	rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,  				CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN); @@ -235,6 +292,9 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0);  	rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); +	if (tsc->zone->ops->set_trips) +		rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, +					IRQ_TEMPD1 | IRQ_TEMP2);  	reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);  	reg_val |= THCTR_THSST; @@ -303,6 +363,34 @@ static void rcar_gen3_hwmon_action(void *data)  	thermal_remove_hwmon_sysfs(zone);  } +static int rcar_gen3_thermal_request_irqs(struct rcar_gen3_thermal_priv *priv, +					  struct platform_device *pdev) +{ +	struct device *dev = &pdev->dev; +	unsigned int i; +	char *irqname; +	int ret, irq; + +	for (i = 0; i < 2; i++) { +		irq = platform_get_irq_optional(pdev, i); +		if (irq < 0) +			return irq; + +		irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d", +					 dev_name(dev), i); +		if (!irqname) +			return -ENOMEM; + +		ret = devm_request_threaded_irq(dev, irq, NULL, +						rcar_gen3_thermal_irq, +						IRQF_ONESHOT, irqname, priv); +		if (ret) +			return ret; +	} + +	return 0; +} +  static int rcar_gen3_thermal_probe(struct platform_device *pdev)  {  	struct rcar_gen3_thermal_priv *priv; @@ -326,6 +414,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, priv); +	if (rcar_gen3_thermal_request_irqs(priv, pdev)) +		rcar_gen3_tz_of_ops.set_trips = NULL; +  	pm_runtime_enable(dev);  	pm_runtime_get_sync(dev); @@ -351,9 +442,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)  		priv->tscs[i] = tsc; -		priv->thermal_init(tsc); -		rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1); -  		zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,  							    &rcar_gen3_tz_of_ops);  		if (IS_ERR(zone)) { @@ -363,6 +451,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)  		}  		tsc->zone = zone; +		priv->thermal_init(tsc); +		rcar_gen3_thermal_calc_coefs(tsc, ptat, thcodes[i], *ths_tj_1); +  		tsc->zone->tzp->no_hwmon = false;  		ret = thermal_add_hwmon_sysfs(tsc->zone);  		if (ret) @@ -401,8 +492,12 @@ static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)  	for (i = 0; i < priv->num_tscs; i++) {  		struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; +		struct thermal_zone_device *zone = tsc->zone;  		priv->thermal_init(tsc); +		if (zone->ops->set_trips) +			rcar_gen3_thermal_set_trips(tsc, zone->prev_low_trip, +						    zone->prev_high_trip);  	}  	return 0; | 
