Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb6c01c2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull thermal management fixes from Zhang Rui:

 - fix a regression that thermal zone dynamically allocated sysfs
   attributes are freed before they're removed, which is introduced in
   4.10-rc1 (Jacob von Chorus)

 - fix a boot warning because deprecated hwmon API is used (Fabio
   Estevam)

 - a couple of fixes for rockchip thermal driver (Brian Norris, Caesar
   Wang)

* 'for-rc' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux:
  thermal: rockchip: fixes the conversion table
  thermal: core: move tz->device.groups cleanup to thermal_release
  thermal: thermal_hwmon: Convert to hwmon_device_register_with_info()
  thermal: rockchip: handle set_trips without the trip points
  thermal: rockchip: optimize the conversion table
  thermal: rockchip: fixes invalid temperature case
  thermal: rockchip: don't pass table structs by value
  thermal: rockchip: improve conversion error messages
parents c497f8d1 bad94f80
Loading
Loading
Loading
Loading
+100 −53
Original line number Original line Diff line number Diff line
@@ -118,11 +118,11 @@ struct rockchip_tsadc_chip {
	void (*control)(void __iomem *reg, bool on);
	void (*control)(void __iomem *reg, bool on);


	/* Per-sensor methods */
	/* Per-sensor methods */
	int (*get_temp)(struct chip_tsadc_table table,
	int (*get_temp)(const struct chip_tsadc_table *table,
			int chn, void __iomem *reg, int *temp);
			int chn, void __iomem *reg, int *temp);
	void (*set_alarm_temp)(struct chip_tsadc_table table,
	int (*set_alarm_temp)(const struct chip_tsadc_table *table,
			      int chn, void __iomem *reg, int temp);
			      int chn, void __iomem *reg, int temp);
	void (*set_tshut_temp)(struct chip_tsadc_table table,
	int (*set_tshut_temp)(const struct chip_tsadc_table *table,
			      int chn, void __iomem *reg, int temp);
			      int chn, void __iomem *reg, int temp);
	void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
	void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);


@@ -317,6 +317,7 @@ static const struct tsadc_table rk3288_code_table[] = {
	{3452, 115000},
	{3452, 115000},
	{3437, 120000},
	{3437, 120000},
	{3421, 125000},
	{3421, 125000},
	{0, 125000},
};
};


static const struct tsadc_table rk3368_code_table[] = {
static const struct tsadc_table rk3368_code_table[] = {
@@ -397,59 +398,80 @@ static const struct tsadc_table rk3399_code_table[] = {
	{TSADCV3_DATA_MASK, 125000},
	{TSADCV3_DATA_MASK, 125000},
};
};


static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table,
static u32 rk_tsadcv2_temp_to_code(const struct chip_tsadc_table *table,
				   int temp)
				   int temp)
{
{
	int high, low, mid;
	int high, low, mid;
	u32 error = 0;
	unsigned long num;
	unsigned int denom;
	u32 error = table->data_mask;


	low = 0;
	low = 0;
	high = table.length - 1;
	high = (table->length - 1) - 1; /* ignore the last check for table */
	mid = (high + low) / 2;
	mid = (high + low) / 2;


	/* Return mask code data when the temp is over table range */
	/* Return mask code data when the temp is over table range */
	if (temp < table.id[low].temp || temp > table.id[high].temp) {
	if (temp < table->id[low].temp || temp > table->id[high].temp)
		error = table.data_mask;
		goto exit;
		goto exit;
	}


	while (low <= high) {
	while (low <= high) {
		if (temp == table.id[mid].temp)
		if (temp == table->id[mid].temp)
			return table.id[mid].code;
			return table->id[mid].code;
		else if (temp < table.id[mid].temp)
		else if (temp < table->id[mid].temp)
			high = mid - 1;
			high = mid - 1;
		else
		else
			low = mid + 1;
			low = mid + 1;
		mid = (low + high) / 2;
		mid = (low + high) / 2;
	}
	}


	/*
	 * The conversion code granularity provided by the table. Let's
	 * assume that the relationship between temperature and
	 * analog value between 2 table entries is linear and interpolate
	 * to produce less granular result.
	 */
	num = abs(table->id[mid + 1].code - table->id[mid].code);
	num *= temp - table->id[mid].temp;
	denom = table->id[mid + 1].temp - table->id[mid].temp;

	switch (table->mode) {
	case ADC_DECREMENT:
		return table->id[mid].code - (num / denom);
	case ADC_INCREMENT:
		return table->id[mid].code + (num / denom);
	default:
		pr_err("%s: unknown table mode: %d\n", __func__, table->mode);
		return error;
	}

exit:
exit:
	pr_err("Invalid the conversion, error=%d\n", error);
	pr_err("%s: invalid temperature, temp=%d error=%d\n",
	       __func__, temp, error);
	return error;
	return error;
}
}


static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
static int rk_tsadcv2_code_to_temp(const struct chip_tsadc_table *table,
				   int *temp)
				   u32 code, int *temp)
{
{
	unsigned int low = 1;
	unsigned int low = 1;
	unsigned int high = table.length - 1;
	unsigned int high = table->length - 1;
	unsigned int mid = (low + high) / 2;
	unsigned int mid = (low + high) / 2;
	unsigned int num;
	unsigned int num;
	unsigned long denom;
	unsigned long denom;


	WARN_ON(table.length < 2);
	WARN_ON(table->length < 2);


	switch (table.mode) {
	switch (table->mode) {
	case ADC_DECREMENT:
	case ADC_DECREMENT:
		code &= table.data_mask;
		code &= table->data_mask;
		if (code < table.id[high].code)
		if (code <= table->id[high].code)
			return -EAGAIN;		/* Incorrect reading */
			return -EAGAIN;		/* Incorrect reading */


		while (low <= high) {
		while (low <= high) {
			if (code >= table.id[mid].code &&
			if (code >= table->id[mid].code &&
			    code < table.id[mid - 1].code)
			    code < table->id[mid - 1].code)
				break;
				break;
			else if (code < table.id[mid].code)
			else if (code < table->id[mid].code)
				low = mid + 1;
				low = mid + 1;
			else
			else
				high = mid - 1;
				high = mid - 1;
@@ -458,15 +480,15 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
		}
		}
		break;
		break;
	case ADC_INCREMENT:
	case ADC_INCREMENT:
		code &= table.data_mask;
		code &= table->data_mask;
		if (code < table.id[low].code)
		if (code < table->id[low].code)
			return -EAGAIN;		/* Incorrect reading */
			return -EAGAIN;		/* Incorrect reading */


		while (low <= high) {
		while (low <= high) {
			if (code <= table.id[mid].code &&
			if (code <= table->id[mid].code &&
			    code > table.id[mid - 1].code)
			    code > table->id[mid - 1].code)
				break;
				break;
			else if (code > table.id[mid].code)
			else if (code > table->id[mid].code)
				low = mid + 1;
				low = mid + 1;
			else
			else
				high = mid - 1;
				high = mid - 1;
@@ -475,7 +497,8 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
		}
		}
		break;
		break;
	default:
	default:
		pr_err("Invalid the conversion table\n");
		pr_err("%s: unknown table mode: %d\n", __func__, table->mode);
		return -EINVAL;
	}
	}


	/*
	/*
@@ -484,10 +507,10 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
	 * temperature between 2 table entries is linear and interpolate
	 * temperature between 2 table entries is linear and interpolate
	 * to produce less granular result.
	 * to produce less granular result.
	 */
	 */
	num = table.id[mid].temp - table.id[mid - 1].temp;
	num = table->id[mid].temp - table->id[mid - 1].temp;
	num *= abs(table.id[mid - 1].code - code);
	num *= abs(table->id[mid - 1].code - code);
	denom = abs(table.id[mid - 1].code - table.id[mid].code);
	denom = abs(table->id[mid - 1].code - table->id[mid].code);
	*temp = table.id[mid - 1].temp + (num / denom);
	*temp = table->id[mid - 1].temp + (num / denom);


	return 0;
	return 0;
}
}
@@ -638,7 +661,7 @@ static void rk_tsadcv3_control(void __iomem *regs, bool enable)
	writel_relaxed(val, regs + TSADCV2_AUTO_CON);
	writel_relaxed(val, regs + TSADCV2_AUTO_CON);
}
}


static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
static int rk_tsadcv2_get_temp(const struct chip_tsadc_table *table,
			       int chn, void __iomem *regs, int *temp)
			       int chn, void __iomem *regs, int *temp)
{
{
	u32 val;
	u32 val;
@@ -648,39 +671,57 @@ static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
	return rk_tsadcv2_code_to_temp(table, val, temp);
	return rk_tsadcv2_code_to_temp(table, val, temp);
}
}


static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table,
static int rk_tsadcv2_alarm_temp(const struct chip_tsadc_table *table,
				 int chn, void __iomem *regs, int temp)
				 int chn, void __iomem *regs, int temp)
{
{
	u32 alarm_value, int_en;
	u32 alarm_value;
	u32 int_en, int_clr;

	/*
	 * In some cases, some sensors didn't need the trip points, the
	 * set_trips will pass {-INT_MAX, INT_MAX} to trigger tsadc alarm
	 * in the end, ignore this case and disable the high temperature
	 * interrupt.
	 */
	if (temp == INT_MAX) {
		int_clr = readl_relaxed(regs + TSADCV2_INT_EN);
		int_clr &= ~TSADCV2_INT_SRC_EN(chn);
		writel_relaxed(int_clr, regs + TSADCV2_INT_EN);
		return 0;
	}


	/* Make sure the value is valid */
	/* Make sure the value is valid */
	alarm_value = rk_tsadcv2_temp_to_code(table, temp);
	alarm_value = rk_tsadcv2_temp_to_code(table, temp);
	if (alarm_value == table.data_mask)
	if (alarm_value == table->data_mask)
		return;
		return -ERANGE;


	writel_relaxed(alarm_value & table.data_mask,
	writel_relaxed(alarm_value & table->data_mask,
		       regs + TSADCV2_COMP_INT(chn));
		       regs + TSADCV2_COMP_INT(chn));


	int_en = readl_relaxed(regs + TSADCV2_INT_EN);
	int_en = readl_relaxed(regs + TSADCV2_INT_EN);
	int_en |= TSADCV2_INT_SRC_EN(chn);
	int_en |= TSADCV2_INT_SRC_EN(chn);
	writel_relaxed(int_en, regs + TSADCV2_INT_EN);
	writel_relaxed(int_en, regs + TSADCV2_INT_EN);

	return 0;
}
}


static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table,
static int rk_tsadcv2_tshut_temp(const struct chip_tsadc_table *table,
				 int chn, void __iomem *regs, int temp)
				 int chn, void __iomem *regs, int temp)
{
{
	u32 tshut_value, val;
	u32 tshut_value, val;


	/* Make sure the value is valid */
	/* Make sure the value is valid */
	tshut_value = rk_tsadcv2_temp_to_code(table, temp);
	tshut_value = rk_tsadcv2_temp_to_code(table, temp);
	if (tshut_value == table.data_mask)
	if (tshut_value == table->data_mask)
		return;
		return -ERANGE;


	writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn));
	writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn));


	/* TSHUT will be valid */
	/* TSHUT will be valid */
	val = readl_relaxed(regs + TSADCV2_AUTO_CON);
	val = readl_relaxed(regs + TSADCV2_AUTO_CON);
	writel_relaxed(val | TSADCV2_AUTO_SRC_EN(chn), regs + TSADCV2_AUTO_CON);
	writel_relaxed(val | TSADCV2_AUTO_SRC_EN(chn), regs + TSADCV2_AUTO_CON);

	return 0;
}
}


static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
@@ -883,10 +924,8 @@ static int rockchip_thermal_set_trips(void *_sensor, int low, int high)
	dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n",
	dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n",
		__func__, sensor->id, low, high);
		__func__, sensor->id, low, high);


	tsadc->set_alarm_temp(tsadc->table,
	return tsadc->set_alarm_temp(&tsadc->table,
				     sensor->id, thermal->regs, high);
				     sensor->id, thermal->regs, high);

	return 0;
}
}


static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
@@ -896,7 +935,7 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
	const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip;
	const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip;
	int retval;
	int retval;


	retval = tsadc->get_temp(tsadc->table,
	retval = tsadc->get_temp(&tsadc->table,
				 sensor->id, thermal->regs, out_temp);
				 sensor->id, thermal->regs, out_temp);
	dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n",
	dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n",
		sensor->id, *out_temp, retval);
		sensor->id, *out_temp, retval);
@@ -982,8 +1021,12 @@ rockchip_thermal_register_sensor(struct platform_device *pdev,
	int error;
	int error;


	tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode);
	tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode);
	tsadc->set_tshut_temp(tsadc->table, id, thermal->regs,

	error = tsadc->set_tshut_temp(&tsadc->table, id, thermal->regs,
			      thermal->tshut_temp);
			      thermal->tshut_temp);
	if (error)
		dev_err(&pdev->dev, "%s: invalid tshut=%d, error=%d\n",
			__func__, thermal->tshut_temp, error);


	sensor->thermal = thermal;
	sensor->thermal = thermal;
	sensor->id = id;
	sensor->id = id;
@@ -1196,9 +1239,13 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev)


		thermal->chip->set_tshut_mode(id, thermal->regs,
		thermal->chip->set_tshut_mode(id, thermal->regs,
					      thermal->tshut_mode);
					      thermal->tshut_mode);
		thermal->chip->set_tshut_temp(thermal->chip->table,

		error = thermal->chip->set_tshut_temp(&thermal->chip->table,
					      id, thermal->regs,
					      id, thermal->regs,
					      thermal->tshut_temp);
					      thermal->tshut_temp);
		if (error)
			dev_err(&pdev->dev, "%s: invalid tshut=%d, error=%d\n",
				__func__, thermal->tshut_temp, error);
	}
	}


	thermal->chip->control(thermal->regs, true);
	thermal->chip->control(thermal->regs, true);
+5 −5
Original line number Original line Diff line number Diff line
@@ -799,6 +799,11 @@ static void thermal_release(struct device *dev)
	if (!strncmp(dev_name(dev), "thermal_zone",
	if (!strncmp(dev_name(dev), "thermal_zone",
		     sizeof("thermal_zone") - 1)) {
		     sizeof("thermal_zone") - 1)) {
		tz = to_thermal_zone(dev);
		tz = to_thermal_zone(dev);
		kfree(tz->trip_type_attrs);
		kfree(tz->trip_temp_attrs);
		kfree(tz->trip_hyst_attrs);
		kfree(tz->trips_attribute_group.attrs);
		kfree(tz->device.groups);
		kfree(tz);
		kfree(tz);
	} else if (!strncmp(dev_name(dev), "cooling_device",
	} else if (!strncmp(dev_name(dev), "cooling_device",
			    sizeof("cooling_device") - 1)) {
			    sizeof("cooling_device") - 1)) {
@@ -1305,10 +1310,6 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)


	thermal_zone_device_set_polling(tz, 0);
	thermal_zone_device_set_polling(tz, 0);


	kfree(tz->trip_type_attrs);
	kfree(tz->trip_temp_attrs);
	kfree(tz->trip_hyst_attrs);
	kfree(tz->trips_attribute_group.attrs);
	thermal_set_governor(tz, NULL);
	thermal_set_governor(tz, NULL);


	thermal_remove_hwmon_sysfs(tz);
	thermal_remove_hwmon_sysfs(tz);
@@ -1316,7 +1317,6 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
	idr_destroy(&tz->idr);
	idr_destroy(&tz->idr);
	mutex_destroy(&tz->lock);
	mutex_destroy(&tz->lock);
	device_unregister(&tz->device);
	device_unregister(&tz->device);
	kfree(tz->device.groups);
}
}
EXPORT_SYMBOL_GPL(thermal_zone_device_unregister);
EXPORT_SYMBOL_GPL(thermal_zone_device_unregister);


+3 −17
Original line number Original line Diff line number Diff line
@@ -58,14 +58,6 @@ static LIST_HEAD(thermal_hwmon_list);


static DEFINE_MUTEX(thermal_hwmon_list_lock);
static DEFINE_MUTEX(thermal_hwmon_list_lock);


static ssize_t
name_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
	return sprintf(buf, "%s\n", hwmon->type);
}
static DEVICE_ATTR_RO(name);

static ssize_t
static ssize_t
temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
{
{
@@ -165,15 +157,12 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)


	INIT_LIST_HEAD(&hwmon->tz_list);
	INIT_LIST_HEAD(&hwmon->tz_list);
	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
	hwmon->device = hwmon_device_register(NULL);
	hwmon->device = hwmon_device_register_with_info(NULL, hwmon->type,
							hwmon, NULL, NULL);
	if (IS_ERR(hwmon->device)) {
	if (IS_ERR(hwmon->device)) {
		result = PTR_ERR(hwmon->device);
		result = PTR_ERR(hwmon->device);
		goto free_mem;
		goto free_mem;
	}
	}
	dev_set_drvdata(hwmon->device, hwmon);
	result = device_create_file(hwmon->device, &dev_attr_name);
	if (result)
		goto free_mem;


 register_sys_interface:
 register_sys_interface:
	temp = kzalloc(sizeof(*temp), GFP_KERNEL);
	temp = kzalloc(sizeof(*temp), GFP_KERNEL);
@@ -222,10 +211,8 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
 free_temp_mem:
 free_temp_mem:
	kfree(temp);
	kfree(temp);
 unregister_name:
 unregister_name:
	if (new_hwmon_device) {
	if (new_hwmon_device)
		device_remove_file(hwmon->device, &dev_attr_name);
		hwmon_device_unregister(hwmon->device);
		hwmon_device_unregister(hwmon->device);
	}
 free_mem:
 free_mem:
	if (new_hwmon_device)
	if (new_hwmon_device)
		kfree(hwmon);
		kfree(hwmon);
@@ -267,7 +254,6 @@ void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
	list_del(&hwmon->node);
	list_del(&hwmon->node);
	mutex_unlock(&thermal_hwmon_list_lock);
	mutex_unlock(&thermal_hwmon_list_lock);


	device_remove_file(hwmon->device, &dev_attr_name);
	hwmon_device_unregister(hwmon->device);
	hwmon_device_unregister(hwmon->device);
	kfree(hwmon);
	kfree(hwmon);
}
}