aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/emc2305.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/emc2305.c')
-rw-r--r--drivers/hwmon/emc2305.c71
1 files changed, 69 insertions, 2 deletions
diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c
index 60809289f816..ccfed1be775a 100644
--- a/drivers/hwmon/emc2305.c
+++ b/drivers/hwmon/emc2305.c
@@ -15,12 +15,13 @@
#include <linux/of_device.h>
#include <linux/util_macros.h>
+#define EMC2305_REG_FAN_STATUS 0x24
+#define EMC2305_REG_FAN_STALL_STATUS 0x25
#define EMC2305_REG_DRIVE_FAIL_STATUS 0x27
#define EMC2305_REG_VENDOR 0xfe
#define EMC2305_FAN_MAX 0xff
#define EMC2305_FAN_MIN 0x00
#define EMC2305_FAN_MAX_STATE 10
-#define EMC2305_DEVICE 0x34
#define EMC2305_VENDOR 0x5d
#define EMC2305_REG_PRODUCT_ID 0xfd
#define EMC2305_TACH_REGS_UNUSE_BITS 3
@@ -45,6 +46,7 @@
#define EMC2305_RPM_FACTOR 3932160
#define EMC2305_REG_FAN_DRIVE(n) (0x30 + 0x10 * (n))
+#define EMC2305_REG_FAN_CFG(n) (0x32 + 0x10 * (n))
#define EMC2305_REG_FAN_MIN_DRIVE(n) (0x38 + 0x10 * (n))
#define EMC2305_REG_FAN_TACH(n) (0x3e + 0x10 * (n))
@@ -67,6 +69,15 @@ static const struct i2c_device_id emc2305_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, emc2305_ids);
+static const struct of_device_id emc2305_dt_ids[] = {
+ { .compatible = "microchip,emc2305" },
+ { .compatible = "microchip,emc2303" },
+ { .compatible = "microchip,emc2302" },
+ { .compatible = "microchip,emc2301" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, emc2305_dt_ids);
+
/**
* struct emc2305_cdev_data - device-specific cooling device state
* @cdev: cooling device
@@ -117,6 +128,7 @@ struct emc2305_data {
u8 pwm_polarity_mask;
bool pwm_separate;
u8 pwm_min[EMC2305_PWM_MAX];
+ u8 pwm_max;
u16 pwm_freq[EMC2305_PWM_MAX];
struct emc2305_cdev_data cdev_data[EMC2305_PWM_MAX];
};
@@ -288,7 +300,7 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel)
struct i2c_client *client = data->client;
int ret;
- if (val < data->pwm_min[channel] || val > EMC2305_FAN_MAX)
+ if (val < data->pwm_min[channel] || val > data->pwm_max)
return -EINVAL;
ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(channel), val);
@@ -299,6 +311,49 @@ static int emc2305_set_pwm(struct device *dev, long val, int channel)
return 0;
}
+static int emc2305_get_tz_of(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ struct emc2305_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+ u8 val;
+ int i;
+
+ /* OF parameters are optional - overwrite default setting
+ * if some of them are provided.
+ */
+
+ ret = of_property_read_u8(np, "emc2305,cooling-levels", &val);
+ if (!ret)
+ data->max_state = val;
+ else if (ret != -EINVAL)
+ return ret;
+
+ ret = of_property_read_u8(np, "emc2305,pwm-max", &val);
+ if (!ret)
+ data->pwm_max = val;
+ else if (ret != -EINVAL)
+ return ret;
+
+ ret = of_property_read_u8(np, "emc2305,pwm-min", &val);
+ if (!ret)
+ for (i = 0; i < EMC2305_PWM_MAX; i++)
+ data->pwm_min[i] = val;
+ else if (ret != -EINVAL)
+ return ret;
+
+ /* Not defined or 0 means one thermal zone over all cooling devices.
+ * Otherwise - separated thermal zones for each PWM channel.
+ */
+ ret = of_property_read_u8(np, "emc2305,pwm-channel", &val);
+ if (!ret)
+ data->pwm_separate = (val != 0);
+ else if (ret != -EINVAL)
+ return ret;
+
+ return 0;
+}
+
static int emc2305_set_single_tz(struct device *dev, struct device_node *fan_node, int idx)
{
struct emc2305_data *data = dev_get_drvdata(dev);
@@ -672,6 +727,12 @@ static int emc2305_probe(struct i2c_client *client)
data->pwm_separate = false;
for (i = 0; i < EMC2305_PWM_MAX; i++)
data->pwm_min[i] = EMC2305_FAN_MIN;
+ data->pwm_max = EMC2305_FAN_MAX;
+ if (dev->of_node) {
+ ret = emc2305_get_tz_of(dev);
+ if (ret < 0)
+ return ret;
+ }
}
data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "emc2305", data,
@@ -713,6 +774,12 @@ static int emc2305_probe(struct i2c_client *client)
return ret;
}
+ /* Acknowledge any existing faults. Stops the device responding on the
+ * SMBus alert address.
+ */
+ i2c_smbus_read_byte_data(client, EMC2305_REG_FAN_STALL_STATUS);
+ i2c_smbus_read_byte_data(client, EMC2305_REG_FAN_STATUS);
+
return 0;
}