[patch v1 2/2] mlxsw: core: add support for the external thermal zone setting (by DTS)

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

 




It allows:
- thermal zone setting for mlxsw based HW and from DTS file;
- binding ASIC temperature sensor to  cooling devices.
It requires setting of CONFIG_OF.

Signed-off-by: Vadim Pasternak <vadimp@xxxxxxxxxxxx>
---
 drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 107 ++++++++++++++++++++-
 drivers/net/ethernet/mellanox/mlxsw/minimal.c      |   6 ++
 2 files changed, 109 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index d866c98..c30783e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -34,6 +34,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/device.h>
+#include <linux/of_platform.h>
 #include <linux/sysfs.h>
 #include <linux/thermal.h>
 #include <linux/err.h>
@@ -44,6 +45,7 @@
 #define MLXSW_THERMAL_MAX_TEMP	110000	/* 110C */
 #define MLXSW_THERMAL_MAX_STATE	10
 #define MLXSW_THERMAL_MAX_DUTY	255
+#define MLXSW_THERMAL_TRIP_ELEM	4
 
 struct mlxsw_thermal_trip {
 	int	type;
@@ -98,6 +100,8 @@ struct mlxsw_thermal {
 	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
 	enum thermal_device_mode mode;
+	int ntrips;
+	bool cooling_external;
 };
 
 static inline u8 mlxsw_state_to_duty(int state)
@@ -121,6 +125,10 @@ static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal,
 		if (thermal->cdevs[i] == cdev)
 			return i;
 
+	/* Allow external cooling binding if theres is no local. */
+	if (thermal->cooling_external)
+		return 0;
+
 	return -ENODEV;
 }
 
@@ -334,6 +342,83 @@ static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
 	.set_cur_state	= mlxsw_thermal_set_cur_state,
 };
 
+#ifdef CONFIG_OF
+static int
+mlxsw_thermal_of_init(struct device *dev, struct mlxsw_thermal *thermal)
+{
+	struct device_node *np = dev->of_node;
+	u32 trip[MLXSW_THERMAL_TRIP_ELEM];
+	struct platform_device *pdev;
+	struct device_node *phandle;
+	struct device_node *gchild;
+	struct device_node *child;
+	int ntrips;
+	int i;
+	int ret;
+
+	/* trips */
+	child = of_get_child_by_name(np, "trips");
+
+	/* No trips provided */
+	if (!child) {
+		of_node_put(child);
+		return -EINVAL;
+	}
+
+	/* Cooling device is optional parameter. If it is not defined, driver
+	 * will try to connect PWM which is owned, if any.
+	 */
+	phandle = of_parse_phandle(child, "cooling-phandle", 0);
+	if (phandle) {
+		pdev = of_find_device_by_node(phandle);
+		of_node_put(phandle);
+		if (!pdev) {
+			ret = -ENODEV;
+			goto put_child;
+		}
+
+		thermal->cooling_external = true;
+	}
+
+	ntrips = of_get_child_count(child);
+	if (ntrips == 0) {
+		/* should have at least one child */
+		ret = 0;
+		goto put_child;
+	}
+
+	i = 0;
+	for_each_child_of_node(child, gchild) {
+		ret = of_property_count_u32_elems(gchild, "trip");
+		if (ret != MLXSW_THERMAL_TRIP_ELEM) {
+			ret = -EINVAL;
+			goto put_child;
+		}
+
+		ret = of_property_read_u32_array(gchild, "trip",
+						 trip, ret);
+		if (ret)
+			goto put_gchild;
+
+		memcpy(&thermal->trips[i++], trip, sizeof(trip));
+	}
+	ret = ntrips;
+
+put_gchild:
+	of_node_put(gchild);
+put_child:
+	of_node_put(child);
+
+	return ret;
+}
+#else
+static int
+mlxsw_thermal_of_init(struct device *dev, struct mlxsw_thermal *thermal)
+{
+	return 0;
+}
+#endif
+
 int mlxsw_thermal_init(struct mlxsw_core *core,
 		       const struct mlxsw_bus_info *bus_info,
 		       struct mlxsw_thermal **p_thermal)
@@ -344,7 +429,9 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 	struct mlxsw_thermal *thermal;
 	u16 tacho_active;
 	u8 pwm_active;
-	int err, i;
+	int ntrips;
+	int i;
+	int err;
 
 	thermal = devm_kzalloc(dev, sizeof(*thermal),
 			       GFP_KERNEL);
@@ -353,7 +440,19 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 
 	thermal->core = core;
 	thermal->bus_info = bus_info;
-	memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips));
+
+	if (dev->of_node) {
+		ntrips = mlxsw_thermal_of_init(dev, thermal);
+		if (ntrips > 0)
+			thermal->ntrips = ntrips;
+	}
+
+	if (!dev->of_node || ntrips <= 0) {
+		/* Use default if the external setting is not available */
+		memcpy(thermal->trips, default_thermal_trips,
+		       sizeof(thermal->trips));
+		thermal->ntrips = MLXSW_THERMAL_NUM_TRIPS;
+	}
 
 	err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl);
 	if (err) {
@@ -398,8 +497,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 	}
 
 	thermal->tzdev = thermal_zone_device_register("mlxsw",
-						      MLXSW_THERMAL_NUM_TRIPS,
-						      MLXSW_THERMAL_TRIP_MASK,
+						      thermal->ntrips,
+						      BIT(thermal->ntrips) - 1,
 						      thermal,
 						      &mlxsw_thermal_ops,
 						      NULL, 0,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
index 3dd1626..8e3cc13 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
@@ -56,8 +56,14 @@ static const struct i2c_device_id mlxsw_minimal_i2c_id[] = {
 	{ },
 };
 
+static const struct of_device_id mlxsw_minimal_dt_match[] = {
+	{ .compatible = "mellanox,mlxsw_minimal" },
+	{ },
+};
+
 static struct i2c_driver mlxsw_minimal_i2c_driver = {
 	.driver.name = "mlxsw_minimal",
+	.driver.of_match_table = of_match_ptr(mlxsw_minimal_dt_match),
 	.class = I2C_CLASS_HWMON,
 	.id_table = mlxsw_minimal_i2c_id,
 };
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[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