X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fhwmon%2Femc1403.c;h=1ea7ca510f84a3ca74e75464a4f95d10a22262ef;hb=5aad1daf21f793af23b7b155a9c0aae7ded97f77;hp=361f50b221bd0cb3ffb67d1ff6ab58a52f9c45e9;hpb=d1f7a4c0bfda09bebb1948e2169a6ce6a7319bd3;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c index 361f50b221bd..1ea7ca510f84 100644 --- a/drivers/hwmon/emc1403.c +++ b/drivers/hwmon/emc1403.c @@ -18,10 +18,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * TODO - * - cache alarm and critical limit registers - * - add emc1404 support */ #include @@ -33,60 +29,60 @@ #include #include #include -#include +#include #define THERMAL_PID_REG 0xfd #define THERMAL_SMSC_ID_REG 0xfe #define THERMAL_REVISION_REG 0xff +enum emc1403_chip { emc1402, emc1403, emc1404 }; + struct thermal_data { - struct device *hwmon_dev; + struct regmap *regmap; struct mutex mutex; - /* - * Cache the hyst value so we don't keep re-reading it. In theory - * we could cache it forever as nobody else should be writing it. - */ - u8 cached_hyst; - unsigned long hyst_valid; + const struct attribute_group *groups[4]; }; static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - int retval = i2c_smbus_read_byte_data(client, sda->index); + struct thermal_data *data = dev_get_drvdata(dev); + unsigned int val; + int retval; + retval = regmap_read(data->regmap, sda->index, &val); if (retval < 0) return retval; - return sprintf(buf, "%d000\n", retval); + return sprintf(buf, "%d000\n", val); } static ssize_t show_bit(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr); - int retval = i2c_smbus_read_byte_data(client, sda->nr); + struct thermal_data *data = dev_get_drvdata(dev); + unsigned int val; + int retval; + retval = regmap_read(data->regmap, sda->nr, &val); if (retval < 0) return retval; - retval &= sda->index; - return sprintf(buf, "%d\n", retval ? 1 : 0); + return sprintf(buf, "%d\n", !!(val & sda->index)); } static ssize_t store_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); - struct i2c_client *client = to_i2c_client(dev); + struct thermal_data *data = dev_get_drvdata(dev); unsigned long val; int retval; if (kstrtoul(buf, 10, &val)) return -EINVAL; - retval = i2c_smbus_write_byte_data(client, sda->index, - DIV_ROUND_CLOSEST(val, 1000)); + retval = regmap_write(data->regmap, sda->index, + DIV_ROUND_CLOSEST(val, 1000)); if (retval < 0) return retval; return count; @@ -95,61 +91,62 @@ static ssize_t store_temp(struct device *dev, static ssize_t store_bit(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct thermal_data *data = i2c_get_clientdata(client); struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr); + struct thermal_data *data = dev_get_drvdata(dev); unsigned long val; int retval; if (kstrtoul(buf, 10, &val)) return -EINVAL; - mutex_lock(&data->mutex); - retval = i2c_smbus_read_byte_data(client, sda->nr); + retval = regmap_update_bits(data->regmap, sda->nr, sda->index, + val ? sda->index : 0); if (retval < 0) - goto fail; - - retval &= ~sda->index; - if (val) - retval |= sda->index; - - retval = i2c_smbus_write_byte_data(client, sda->index, retval); - if (retval == 0) - retval = count; -fail: - mutex_unlock(&data->mutex); - return retval; + return retval; + return count; } -static ssize_t show_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_hyst_common(struct device *dev, + struct device_attribute *attr, char *buf, + bool is_min) { - struct i2c_client *client = to_i2c_client(dev); - struct thermal_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); + struct thermal_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + unsigned int limit; + unsigned int hyst; int retval; - int hyst; - retval = i2c_smbus_read_byte_data(client, sda->index); + retval = regmap_read(regmap, sda->index, &limit); if (retval < 0) return retval; - if (time_after(jiffies, data->hyst_valid)) { - hyst = i2c_smbus_read_byte_data(client, 0x21); - if (hyst < 0) - return retval; - data->cached_hyst = hyst; - data->hyst_valid = jiffies + HZ; - } - return sprintf(buf, "%d000\n", retval - data->cached_hyst); + retval = regmap_read(regmap, 0x21, &hyst); + if (retval < 0) + return retval; + + return sprintf(buf, "%d000\n", is_min ? limit + hyst : limit - hyst); +} + +static ssize_t show_hyst(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return show_hyst_common(dev, attr, buf, false); +} + +static ssize_t show_min_hyst(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return show_hyst_common(dev, attr, buf, true); } static ssize_t store_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct thermal_data *data = i2c_get_clientdata(client); struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); + struct thermal_data *data = dev_get_drvdata(dev); + struct regmap *regmap = data->regmap; + unsigned int limit; int retval; int hyst; unsigned long val; @@ -158,23 +155,15 @@ static ssize_t store_hyst(struct device *dev, return -EINVAL; mutex_lock(&data->mutex); - retval = i2c_smbus_read_byte_data(client, sda->index); + retval = regmap_read(regmap, sda->index, &limit); if (retval < 0) goto fail; - hyst = retval * 1000 - val; - hyst = DIV_ROUND_CLOSEST(hyst, 1000); - if (hyst < 0 || hyst > 255) { - retval = -ERANGE; - goto fail; - } - - retval = i2c_smbus_write_byte_data(client, 0x21, hyst); - if (retval == 0) { + hyst = limit * 1000 - val; + hyst = clamp_val(DIV_ROUND_CLOSEST(hyst, 1000), 0, 255); + retval = regmap_write(regmap, 0x21, hyst); + if (retval == 0) retval = count; - data->cached_hyst = hyst; - data->hyst_valid = jiffies + HZ; - } fail: mutex_unlock(&data->mutex); return retval; @@ -197,6 +186,8 @@ static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x01); static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x01); +static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x06); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_hyst, NULL, 0x05); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_hyst, store_hyst, 0x20); @@ -207,14 +198,16 @@ static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x19); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0x01); +static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_bit, NULL, 0x36, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x02); static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x02); -static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO | S_IWUSR, - show_hyst, store_hyst, 0x19); +static SENSOR_DEVICE_ATTR(temp2_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x08); +static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_hyst, NULL, 0x07); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_hyst, NULL, 0x19); static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x16); @@ -223,49 +216,141 @@ static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO | S_IWUSR, show_temp, store_temp, 0x1A); static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 0x23); +static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_bit, NULL, 0x36, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_bit, NULL, 0x35, 0x04); static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_bit, NULL, 0x37, 0x04); -static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO | S_IWUSR, - show_hyst, store_hyst, 0x1A); +static SENSOR_DEVICE_ATTR(temp3_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x16); +static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_hyst, NULL, 0x15); +static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_hyst, NULL, 0x1A); + +static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x2D); +static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x2C); +static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0x30); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 0x2A); +static SENSOR_DEVICE_ATTR_2(temp4_fault, S_IRUGO, show_bit, NULL, 0x1b, 0x08); +static SENSOR_DEVICE_ATTR_2(temp4_min_alarm, S_IRUGO, + show_bit, NULL, 0x36, 0x08); +static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, + show_bit, NULL, 0x35, 0x08); +static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO, + show_bit, NULL, 0x37, 0x08); +static SENSOR_DEVICE_ATTR(temp4_min_hyst, S_IRUGO, show_min_hyst, NULL, 0x2D); +static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_hyst, NULL, 0x2C); +static SENSOR_DEVICE_ATTR(temp4_crit_hyst, S_IRUGO, show_hyst, NULL, 0x30); static SENSOR_DEVICE_ATTR_2(power_state, S_IRUGO | S_IWUSR, show_bit, store_bit, 0x03, 0x40); -static struct attribute *mid_att_thermal[] = { +static struct attribute *emc1402_attrs[] = { &sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, - &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, - &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, + + &sensor_dev_attr_power_state.dev_attr.attr, + NULL +}; + +static const struct attribute_group emc1402_group = { + .attrs = emc1402_attrs, +}; + +static struct attribute *emc1403_attrs[] = { + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + + &sensor_dev_attr_temp2_fault.dev_attr.attr, &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, - &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_crit.dev_attr.attr, &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, - &sensor_dev_attr_power_state.dev_attr.attr, NULL }; -static const struct attribute_group m_thermal_gr = { - .attrs = mid_att_thermal +static const struct attribute_group emc1403_group = { + .attrs = emc1403_attrs, +}; + +static struct attribute *emc1404_attrs[] = { + &sensor_dev_attr_temp4_min.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp4_crit.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_fault.dev_attr.attr, + &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, + &sensor_dev_attr_temp4_min_hyst.dev_attr.attr, + &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp4_crit_hyst.dev_attr.attr, + NULL +}; + +static const struct attribute_group emc1404_group = { + .attrs = emc1404_attrs, +}; + +/* + * EMC14x2 uses a different register and different bits to report alarm and + * fault status. For simplicity, provide a separate attribute group for this + * chip series. + * Since we can not re-use the same attribute names, create a separate attribute + * array. + */ +static struct sensor_device_attribute_2 emc1402_alarms[] = { + SENSOR_ATTR_2(temp1_min_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x20), + SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x40), + SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x01), + + SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_bit, NULL, 0x02, 0x04), + SENSOR_ATTR_2(temp2_min_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x08), + SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x10), + SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_bit, NULL, 0x02, 0x02), +}; + +static struct attribute *emc1402_alarm_attrs[] = { + &emc1402_alarms[0].dev_attr.attr, + &emc1402_alarms[1].dev_attr.attr, + &emc1402_alarms[2].dev_attr.attr, + &emc1402_alarms[3].dev_attr.attr, + &emc1402_alarms[4].dev_attr.attr, + &emc1402_alarms[5].dev_attr.attr, + &emc1402_alarms[6].dev_attr.attr, + NULL, +}; + +static const struct attribute_group emc1402_alarm_group = { + .attrs = emc1402_alarm_attrs, }; static int emc1403_detect(struct i2c_client *client, @@ -280,16 +365,24 @@ static int emc1403_detect(struct i2c_client *client, id = i2c_smbus_read_byte_data(client, THERMAL_PID_REG); switch (id) { + case 0x20: + strlcpy(info->type, "emc1402", I2C_NAME_SIZE); + break; case 0x21: strlcpy(info->type, "emc1403", I2C_NAME_SIZE); break; + case 0x22: + strlcpy(info->type, "emc1422", I2C_NAME_SIZE); + break; case 0x23: strlcpy(info->type, "emc1423", I2C_NAME_SIZE); break; - /* - * Note: 0x25 is the 1404 which is very similar and this - * driver could be extended - */ + case 0x25: + strlcpy(info->type, "emc1404", I2C_NAME_SIZE); + break; + case 0x27: + strlcpy(info->type, "emc1424", I2C_NAME_SIZE); + break; default: return -ENODEV; } @@ -301,56 +394,89 @@ static int emc1403_detect(struct i2c_client *client, return 0; } +static bool emc1403_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0x00: /* internal diode high byte */ + case 0x01: /* external diode 1 high byte */ + case 0x02: /* status */ + case 0x10: /* external diode 1 low byte */ + case 0x1b: /* external diode fault */ + case 0x23: /* external diode 2 high byte */ + case 0x24: /* external diode 2 low byte */ + case 0x29: /* internal diode low byte */ + case 0x2a: /* externl diode 3 high byte */ + case 0x2b: /* external diode 3 low byte */ + case 0x35: /* high limit status */ + case 0x36: /* low limit status */ + case 0x37: /* therm limit status */ + return true; + default: + return false; + } +} + +static const struct regmap_config emc1403_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = emc1403_regmap_is_volatile, +}; + static int emc1403_probe(struct i2c_client *client, const struct i2c_device_id *id) { - int res; struct thermal_data *data; + struct device *hwmon_dev; data = devm_kzalloc(&client->dev, sizeof(struct thermal_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - i2c_set_clientdata(client, data); + data->regmap = devm_regmap_init_i2c(client, &emc1403_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + mutex_init(&data->mutex); - data->hyst_valid = jiffies - 1; /* Expired */ - res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr); - if (res) { - dev_warn(&client->dev, "create group failed\n"); - return res; - } - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - res = PTR_ERR(data->hwmon_dev); - dev_warn(&client->dev, "register hwmon dev failed\n"); - goto thermal_error; + switch (id->driver_data) { + case emc1404: + data->groups[2] = &emc1404_group; + case emc1403: + data->groups[1] = &emc1403_group; + case emc1402: + data->groups[0] = &emc1402_group; } - dev_info(&client->dev, "EMC1403 Thermal chip found\n"); - return 0; -thermal_error: - sysfs_remove_group(&client->dev.kobj, &m_thermal_gr); - return res; -} + if (id->driver_data == emc1402) + data->groups[1] = &emc1402_alarm_group; -static int emc1403_remove(struct i2c_client *client) -{ - struct thermal_data *data = i2c_get_clientdata(client); + hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, + client->name, data, + data->groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &m_thermal_gr); + dev_info(&client->dev, "%s Thermal chip found\n", id->name); return 0; } static const unsigned short emc1403_address_list[] = { - 0x18, 0x29, 0x4c, 0x4d, I2C_CLIENT_END + 0x18, 0x1c, 0x29, 0x4c, 0x4d, 0x5c, I2C_CLIENT_END }; +/* Last digit of chip name indicates number of channels */ static const struct i2c_device_id emc1403_idtable[] = { - { "emc1403", 0 }, - { "emc1423", 0 }, + { "emc1402", emc1402 }, + { "emc1403", emc1403 }, + { "emc1404", emc1404 }, + { "emc1412", emc1402 }, + { "emc1413", emc1403 }, + { "emc1414", emc1404 }, + { "emc1422", emc1402 }, + { "emc1423", emc1403 }, + { "emc1424", emc1404 }, { } }; MODULE_DEVICE_TABLE(i2c, emc1403_idtable); @@ -362,7 +488,6 @@ static struct i2c_driver sensor_emc1403 = { }, .detect = emc1403_detect, .probe = emc1403_probe, - .remove = emc1403_remove, .id_table = emc1403_idtable, .address_list = emc1403_address_list, };