mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	hwmon: (aspeed-pwm-tacho) cooling device support.
Add support in aspeed-pwm-tacho driver for cooling device creation. This cooling device could be bound to a thermal zone for the thermal control. Device will appear in /sys/class/thermal folder as cooling_deviceX. Then it could be bound to particular thermal zones. Allow specification of the cooling levels vector - PWM duty cycle values in a range from 0 to 255 which correspond to thermal cooling states. Signed-off-by: Mykola Kostenok <c_mykolak@mellanox.com> Reviewed-by: Joel Stanley <joel@jms.id.au> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
		
							parent
							
								
									5e047541c1
								
							
						
					
					
						commit
						f198907d2f
					
				
					 1 changed files with 114 additions and 2 deletions
				
			
		| 
						 | 
				
			
			@ -20,6 +20,7 @@
 | 
			
		|||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/sysfs.h>
 | 
			
		||||
#include <linux/regmap.h>
 | 
			
		||||
#include <linux/thermal.h>
 | 
			
		||||
 | 
			
		||||
/* ASPEED PWM & FAN Tach Register Definition */
 | 
			
		||||
#define ASPEED_PTCR_CTRL		0x00
 | 
			
		||||
| 
						 | 
				
			
			@ -166,6 +167,18 @@
 | 
			
		|||
/* How long we sleep in us while waiting for an RPM result. */
 | 
			
		||||
#define ASPEED_RPM_STATUS_SLEEP_USEC	500
 | 
			
		||||
 | 
			
		||||
#define MAX_CDEV_NAME_LEN 16
 | 
			
		||||
 | 
			
		||||
struct aspeed_cooling_device {
 | 
			
		||||
	char name[16];
 | 
			
		||||
	struct aspeed_pwm_tacho_data *priv;
 | 
			
		||||
	struct thermal_cooling_device *tcdev;
 | 
			
		||||
	int pwm_port;
 | 
			
		||||
	u8 *cooling_levels;
 | 
			
		||||
	u8 max_state;
 | 
			
		||||
	u8 cur_state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct aspeed_pwm_tacho_data {
 | 
			
		||||
	struct regmap *regmap;
 | 
			
		||||
	unsigned long clk_freq;
 | 
			
		||||
| 
						 | 
				
			
			@ -180,6 +193,7 @@ struct aspeed_pwm_tacho_data {
 | 
			
		|||
	u8 pwm_port_type[8];
 | 
			
		||||
	u8 pwm_port_fan_ctrl[8];
 | 
			
		||||
	u8 fan_tach_ch_source[16];
 | 
			
		||||
	struct aspeed_cooling_device *cdev[8];
 | 
			
		||||
	const struct attribute_group *groups[3];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -765,6 +779,94 @@ static void aspeed_create_fan_tach_channel(struct aspeed_pwm_tacho_data *priv,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
aspeed_pwm_cz_get_max_state(struct thermal_cooling_device *tcdev,
 | 
			
		||||
			    unsigned long *state)
 | 
			
		||||
{
 | 
			
		||||
	struct aspeed_cooling_device *cdev = tcdev->devdata;
 | 
			
		||||
 | 
			
		||||
	*state = cdev->max_state;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
aspeed_pwm_cz_get_cur_state(struct thermal_cooling_device *tcdev,
 | 
			
		||||
			    unsigned long *state)
 | 
			
		||||
{
 | 
			
		||||
	struct aspeed_cooling_device *cdev = tcdev->devdata;
 | 
			
		||||
 | 
			
		||||
	*state = cdev->cur_state;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
aspeed_pwm_cz_set_cur_state(struct thermal_cooling_device *tcdev,
 | 
			
		||||
			    unsigned long state)
 | 
			
		||||
{
 | 
			
		||||
	struct aspeed_cooling_device *cdev = tcdev->devdata;
 | 
			
		||||
 | 
			
		||||
	if (state > cdev->max_state)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	cdev->cur_state = state;
 | 
			
		||||
	cdev->priv->pwm_port_fan_ctrl[cdev->pwm_port] =
 | 
			
		||||
					cdev->cooling_levels[cdev->cur_state];
 | 
			
		||||
	aspeed_set_pwm_port_fan_ctrl(cdev->priv, cdev->pwm_port,
 | 
			
		||||
				     cdev->cooling_levels[cdev->cur_state]);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct thermal_cooling_device_ops aspeed_pwm_cool_ops = {
 | 
			
		||||
	.get_max_state = aspeed_pwm_cz_get_max_state,
 | 
			
		||||
	.get_cur_state = aspeed_pwm_cz_get_cur_state,
 | 
			
		||||
	.set_cur_state = aspeed_pwm_cz_set_cur_state,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int aspeed_create_pwm_cooling(struct device *dev,
 | 
			
		||||
				     struct device_node *child,
 | 
			
		||||
				     struct aspeed_pwm_tacho_data *priv,
 | 
			
		||||
				     u32 pwm_port, u8 num_levels)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct aspeed_cooling_device *cdev;
 | 
			
		||||
 | 
			
		||||
	cdev = devm_kzalloc(dev, sizeof(*cdev), GFP_KERNEL);
 | 
			
		||||
 | 
			
		||||
	if (!cdev)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	cdev->cooling_levels = devm_kzalloc(dev, num_levels, GFP_KERNEL);
 | 
			
		||||
	if (!cdev->cooling_levels)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	cdev->max_state = num_levels - 1;
 | 
			
		||||
	ret = of_property_read_u8_array(child, "cooling-levels",
 | 
			
		||||
					cdev->cooling_levels,
 | 
			
		||||
					num_levels);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(dev, "Property 'cooling-levels' cannot be read.\n");
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%s%d", child->name, pwm_port);
 | 
			
		||||
 | 
			
		||||
	cdev->tcdev = thermal_of_cooling_device_register(child,
 | 
			
		||||
							 cdev->name,
 | 
			
		||||
							 cdev,
 | 
			
		||||
							 &aspeed_pwm_cool_ops);
 | 
			
		||||
	if (IS_ERR(cdev->tcdev))
 | 
			
		||||
		return PTR_ERR(cdev->tcdev);
 | 
			
		||||
 | 
			
		||||
	cdev->priv = priv;
 | 
			
		||||
	cdev->pwm_port = pwm_port;
 | 
			
		||||
 | 
			
		||||
	priv->cdev[pwm_port] = cdev;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int aspeed_create_fan(struct device *dev,
 | 
			
		||||
			     struct device_node *child,
 | 
			
		||||
			     struct aspeed_pwm_tacho_data *priv)
 | 
			
		||||
| 
						 | 
				
			
			@ -778,6 +880,15 @@ static int aspeed_create_fan(struct device *dev,
 | 
			
		|||
		return ret;
 | 
			
		||||
	aspeed_create_pwm_port(priv, (u8)pwm_port);
 | 
			
		||||
 | 
			
		||||
	ret = of_property_count_u8_elems(child, "cooling-levels");
 | 
			
		||||
 | 
			
		||||
	if (ret > 0) {
 | 
			
		||||
		ret = aspeed_create_pwm_cooling(dev, child, priv, pwm_port,
 | 
			
		||||
						ret);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	count = of_property_count_u8_elems(child, "aspeed,fan-tach-ch");
 | 
			
		||||
	if (count < 1)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
| 
						 | 
				
			
			@ -834,9 +945,10 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
 | 
			
		|||
 | 
			
		||||
	for_each_child_of_node(np, child) {
 | 
			
		||||
		ret = aspeed_create_fan(dev, child, priv);
 | 
			
		||||
		of_node_put(child);
 | 
			
		||||
		if (ret)
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			of_node_put(child);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	priv->groups[0] = &pwm_dev_group;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue