From 51b4164ac0c95b15623c9fbdaf0eea622e377e2f Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Thu, 5 May 2022 15:46:07 +0100 Subject: [PATCH] hwmon: emc2305: fixups for driver submitted to mailing lists The driver had a number of issues, checkpatch warnings/errors, and other limitations, so fix these up to make it usable. Signed-off-by: Phil Elwell Signed-off-by: Dave Stevenson --- drivers/hwmon/emc2305.c | 80 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/drivers/hwmon/emc2305.c b/drivers/hwmon/emc2305.c index aa1f25add0b6b3..fdcc9a779d7558 100644 --- a/drivers/hwmon/emc2305.c +++ b/drivers/hwmon/emc2305.c @@ -15,13 +15,13 @@ static const unsigned short emc2305_normal_i2c[] = { 0x27, 0x2c, 0x2d, 0x2e, 0x2f, 0x4c, 0x4d, I2C_CLIENT_END }; +#define EMC2305_REG_FAN_STATUS 0x24 +#define EMC2305_REG_FAN_STALL_STATUS 0x25 #define EMC2305_REG_DRIVE_FAIL_STATUS 0x27 -#define EMC2305_REG_DEVICE 0xfd #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 @@ -40,6 +40,7 @@ emc2305_normal_i2c[] = { 0x27, 0x2c, 0x2d, 0x2e, 0x2f, 0x4c, 0x4d, I2C_CLIENT_EN #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)) @@ -59,6 +60,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); + /** * @cdev: cooling device; * @curr_state: cooling current state; @@ -102,6 +112,7 @@ struct emc2305_data { u8 pwm_num; bool pwm_separate; u8 pwm_min[EMC2305_PWM_MAX]; + u8 pwm_max; struct emc2305_cdev_data cdev_data[EMC2305_PWM_MAX]; }; @@ -263,7 +274,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); @@ -274,6 +285,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; + u32 val; + int i; + + /* OF parameters are optional - overwrite default setting + * if some of them are provided. + */ + + ret = of_property_read_u32(np, "emc2305,cooling-levels", &val); + if (!ret) + data->max_state = (u8)val; + else if (ret != -EINVAL) + return ret; + + ret = of_property_read_u32(np, "emc2305,pwm-max", &val); + if (!ret) + data->pwm_max = (u8)val; + else if (ret != -EINVAL) + return ret; + + ret = of_property_read_u32(np, "emc2305,pwm-min", &val); + if (!ret) + for (i = 0; i < EMC2305_PWM_MAX; i++) + data->pwm_min[i] = (u8)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_u32(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, int idx) { struct emc2305_data *data = dev_get_drvdata(dev); @@ -524,7 +578,7 @@ static int emc2305_probe(struct i2c_client *client, const struct i2c_device_id * struct device *dev = &client->dev; struct emc2305_data *data; struct emc2305_platform_data *pdata; - int vendor, device; + int vendor; int ret; int i; @@ -535,10 +589,6 @@ static int emc2305_probe(struct i2c_client *client, const struct i2c_device_id * if (vendor != EMC2305_VENDOR) return -ENODEV; - device = i2c_smbus_read_byte_data(client, EMC2305_REG_DEVICE); - if (device != EMC2305_DEVICE) - return -ENODEV; - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -566,11 +616,18 @@ static int emc2305_probe(struct i2c_client *client, const struct i2c_device_id * data->pwm_separate = pdata->pwm_separate; for (i = 0; i < EMC2305_PWM_MAX; i++) data->pwm_min[i] = pdata->pwm_min[i]; + data->pwm_max = EMC2305_FAN_MAX; } else { data->max_state = EMC2305_FAN_MAX_STATE; 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, @@ -591,6 +648,12 @@ static int emc2305_probe(struct i2c_client *client, const struct i2c_device_id * 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; } @@ -606,6 +669,7 @@ static struct i2c_driver emc2305_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "emc2305", + .of_match_table = emc2305_dt_ids, }, .probe = emc2305_probe, .remove = emc2305_remove,