Re: [PATCH 1/2] power: supply: cros_usbpd-charger: extend as a thermal of cooling device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2024-11-22 11:47:21+0800, Sung-Chi Li wrote:
> cros_usbpd-charger is the driver that takes care the system input power
> from the pd charger. This driver also exposes the functionality to limit
> input current.
> 
> We can extend this driver to make it as a passive thermal cooling
> device by limiting the input current. As such, this commit implements
> the required cooling methods and OF style registration.
> 
> Signed-off-by: Sung-Chi Li <lschyi@xxxxxxxxxxxx>
> ---
>  drivers/power/supply/cros_usbpd-charger.c | 98 +++++++++++++++++++++++++++++--
>  1 file changed, 93 insertions(+), 5 deletions(-)

A dependency from CHARGER_CROS_PCHG to THERMAL needs to be added to
drivers/power/supply/Kconfig.

> 
> diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c
> index 47d3f58aa15c..a0451630cdd7 100644
> --- a/drivers/power/supply/cros_usbpd-charger.c
> +++ b/drivers/power/supply/cros_usbpd-charger.c
> @@ -13,6 +13,9 @@
>  #include <linux/platform_device.h>
>  #include <linux/power_supply.h>
>  #include <linux/slab.h>
> +#ifdef CONFIG_THERMAL_OF

Remove this ifdef. The header is perfectly usable in any case.

Actually the CONFIG_THERMAL_OF dependency is not needed at all.
It is only necessary for devm_thermal_of_zone_register() but not 
devm_thermal_of_cooling_device_register() which you are using.
I am confused.

OTOH you are adding the #cooling-cells OF property which itself seems to
be only used by devm_thermal_of_zone_register(), so I'm now even more
confused.

In general, try to also test the driver configurations
!CONFIG_THERMAL_OF and !CONFIG_THERMAL.

> +#include <linux/thermal.h>
> +#endif /* CONFIG_THERMAL_OF */
>  
>  #define CHARGER_USBPD_DIR_NAME			"CROS_USBPD_CHARGER%d"
>  #define CHARGER_DEDICATED_DIR_NAME		"CROS_DEDICATED_CHARGER"
> @@ -22,6 +25,7 @@
>  					 sizeof(CHARGER_DEDICATED_DIR_NAME))
>  #define CHARGER_CACHE_UPDATE_DELAY		msecs_to_jiffies(500)
>  #define CHARGER_MANUFACTURER_MODEL_LENGTH	32
> +#define CHARGER_COOLING_INTERVALS		10
>  
>  #define DRV_NAME "cros-usbpd-charger"
>  
> @@ -76,6 +80,8 @@ static enum power_supply_property cros_usbpd_dedicated_charger_props[] = {
>  /* Input voltage/current limit in mV/mA. Default to none. */
>  static u16 input_voltage_limit = EC_POWER_LIMIT_NONE;
>  static u16 input_current_limit = EC_POWER_LIMIT_NONE;
> +/* Cooling level interns of current limit */
> +static u16 input_current_cooling_level;
>  
>  static bool cros_usbpd_charger_port_is_dedicated(struct port_data *port)
>  {
> @@ -459,13 +465,20 @@ static int cros_usbpd_charger_set_prop(struct power_supply *psy,
>  			break;
>  
>  		input_current_limit = intval;
> -		if (input_current_limit == EC_POWER_LIMIT_NONE)
> +		if (input_current_limit == EC_POWER_LIMIT_NONE) {
>  			dev_info(dev,
>  			  "External Current Limit cleared for all ports\n");
> -		else
> -			dev_info(dev,
> -			  "External Current Limit set to %dmA for all ports\n",
> -			  input_current_limit);
> +			input_current_cooling_level = 0;
> +		} else {
> +			dev_info(
> +				dev,
> +				"External Current Limit set to %dmA for all ports\n",
> +				input_current_limit);
> +			input_current_cooling_level =
> +				input_current_limit *
> +				CHARGER_COOLING_INTERVALS /
> +				port->psy_current_max;

This seems to be a very spammy driver...

> +		}
>  		break;
>  	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
>  		ret = cros_usbpd_charger_set_ext_power_limit(charger,
> @@ -525,6 +538,66 @@ static void cros_usbpd_charger_unregister_notifier(void *data)
>  	cros_usbpd_unregister_notify(&charger->notifier);
>  }
>  
> +#ifdef CONFIG_THERMAL_OF
> +static int
> +cros_usbpd_charger_get_max_cooling_state(struct thermal_cooling_device *cdev,
> +					 unsigned long *cooling_level)
> +{
> +	*cooling_level = CHARGER_COOLING_INTERVALS;
> +	return 0;
> +}
> +
> +static int
> +cros_usbpd_charger_get_cur_cooling_state(struct thermal_cooling_device *cdev,
> +					 unsigned long *cooling_level)
> +{
> +	*cooling_level = input_current_cooling_level;
> +	return 0;
> +}
> +
> +static int
> +cros_usbpd_charger_set_cur_cooling_state(struct thermal_cooling_device *cdev,
> +					 unsigned long cooling_level)
> +{
> +	struct charger_data *charger = cdev->devdata;
> +	struct port_data *port;
> +	int current_limit;
> +	int idx = -1;
> +	int ret;
> +
> +	for (int i = 0; i < charger->num_registered_psy; i++) {
> +		port = charger->ports[i];
> +		if (port->psy_status == POWER_SUPPLY_STATUS_CHARGING) {
> +			idx = i;
> +			break;
> +		}
> +	}

Why not register one cooling device per charger?
It would make things more predictable.
I have no experience with the thermal subsystem, so this is just a
guess.

> +
> +	if (idx == -1)
> +		return -EINVAL;
> +
> +	current_limit =
> +		port->psy_current_max - (cooling_level * port->psy_current_max /
> +					 CHARGER_COOLING_INTERVALS);
> +	ret = cros_usbpd_charger_set_ext_power_limit(charger, current_limit,
> +						     input_voltage_limit);
> +	if (ret < 0)
> +		return ret;
> +
> +	input_current_limit = (current_limit == port->psy_current_max) ?
> +				      EC_POWER_LIMIT_NONE :
> +				      current_limit;
> +	input_current_cooling_level = cooling_level;
> +	return 0;
> +}
> +
> +static struct thermal_cooling_device_ops cros_usbpd_charger_cooling_ops = {

const

> +	.get_max_state = cros_usbpd_charger_get_max_cooling_state,
> +	.get_cur_state = cros_usbpd_charger_get_cur_cooling_state,
> +	.set_cur_state = cros_usbpd_charger_set_cur_cooling_state,
> +};
> +#endif /* CONFIG_THERMAL_OF */
> +
>  static int cros_usbpd_charger_probe(struct platform_device *pd)
>  {
>  	struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
> @@ -534,6 +607,9 @@ static int cros_usbpd_charger_probe(struct platform_device *pd)
>  	struct charger_data *charger;
>  	struct power_supply *psy;
>  	struct port_data *port;
> +#ifdef CONFIG_THERMAL_OF
> +	struct thermal_cooling_device *cdev;
> +#endif /* CONFIG_THERMAL_OF */
>  	int ret = -EINVAL;
>  	int i;
>  
> @@ -674,6 +750,18 @@ static int cros_usbpd_charger_probe(struct platform_device *pd)
>  			goto fail;
>  	}
>  
> +#ifdef CONFIG_THERMAL_OF

Avoid ifdef in .c files.
Use if (IS_ENABLED(CONFIG_THERMAL_OF)) in the normal code flow.
The compiler will optimize away all the unreachable code.

> +	cdev = devm_thermal_of_cooling_device_register(
> +		dev, ec_device->dev->of_node, DRV_NAME, charger,
> +		&cros_usbpd_charger_cooling_ops);
> +	if (IS_ERR(cdev)) {
> +		dev_err(dev,
> +			"Failing register thermal cooling device (err:%pe)\n",
> +			cdev);

dev_err_probe().

> +		goto fail;

Does the call to devm_thermal_of_cooling_device_register() work if there
is no OF configuration?

> +	}
> +#endif /* CONFIG_THERMAL_OF */
> +
>  	return 0;
>  
>  fail:
> 
> -- 
> 2.47.0.371.ga323438b13-goog
> 




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux