mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
hwmon: (lm85) Add support for EMC6D103S
EMC6D103S is similar to EMC6D103, only it does not support registers 62[5:7], 6D[0:7], and 6E[0:7]. Register respective sysfs attributes and update affected registers for all other chips only. Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com> Acked-by: Jean Delvare <khali@linux-fr.org>
This commit is contained in:
parent
4f8ab430fa
commit
06923f8442
2 changed files with 62 additions and 25 deletions
|
@ -26,6 +26,14 @@ Supported chips:
|
|||
Prefix: 'emc6d102'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
Datasheet: http://www.smsc.com/main/catalog/emc6d102.html
|
||||
* SMSC EMC6D103
|
||||
Prefix: 'emc6d103'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
Datasheet: http://www.smsc.com/main/catalog/emc6d103.html
|
||||
* SMSC EMC6D103S
|
||||
Prefix: 'emc6d103s'
|
||||
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||
Datasheet: http://www.smsc.com/main/catalog/emc6d103s.html
|
||||
|
||||
Authors:
|
||||
Philip Pokorny <ppokorny@penguincomputing.com>,
|
||||
|
@ -122,9 +130,11 @@ to be register compatible. The EMC6D100 offers all the features of the
|
|||
EMC6D101 plus additional voltage monitoring and system control features.
|
||||
Unfortunately it is not possible to distinguish between the package
|
||||
versions on register level so these additional voltage inputs may read
|
||||
zero. The EMC6D102 features addtional ADC bits thus extending precision
|
||||
zero. EMC6D102 and EMC6D103 feature additional ADC bits thus extending precision
|
||||
of voltage and temperature channels.
|
||||
|
||||
SMSC EMC6D103S is similar to EMC6D103, but does not support pwm#_auto_pwm_minctl
|
||||
and temp#_auto_temp_off.
|
||||
|
||||
Hardware Configurations
|
||||
-----------------------
|
||||
|
|
|
@ -41,7 +41,7 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
|
|||
enum chips {
|
||||
any_chip, lm85b, lm85c,
|
||||
adm1027, adt7463, adt7468,
|
||||
emc6d100, emc6d102, emc6d103
|
||||
emc6d100, emc6d102, emc6d103, emc6d103s
|
||||
};
|
||||
|
||||
/* The LM85 registers */
|
||||
|
@ -350,6 +350,7 @@ static const struct i2c_device_id lm85_id[] = {
|
|||
{ "emc6d101", emc6d100 },
|
||||
{ "emc6d102", emc6d102 },
|
||||
{ "emc6d103", emc6d103 },
|
||||
{ "emc6d103s", emc6d103s },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm85_id);
|
||||
|
@ -1068,13 +1069,7 @@ static struct attribute *lm85_attributes[] = {
|
|||
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_auto_temp_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_auto_temp_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_auto_temp_min.dev_attr.attr,
|
||||
|
@ -1095,6 +1090,26 @@ static const struct attribute_group lm85_group = {
|
|||
.attrs = lm85_attributes,
|
||||
};
|
||||
|
||||
static struct attribute *lm85_attributes_minctl[] = {
|
||||
&sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr,
|
||||
};
|
||||
|
||||
static const struct attribute_group lm85_group_minctl = {
|
||||
.attrs = lm85_attributes_minctl,
|
||||
};
|
||||
|
||||
static struct attribute *lm85_attributes_temp_off[] = {
|
||||
&sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr,
|
||||
&sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr,
|
||||
};
|
||||
|
||||
static const struct attribute_group lm85_group_temp_off = {
|
||||
.attrs = lm85_attributes_temp_off,
|
||||
};
|
||||
|
||||
static struct attribute *lm85_attributes_in4[] = {
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min.dev_attr.attr,
|
||||
|
@ -1242,16 +1257,9 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|||
case LM85_VERSTEP_EMC6D103_A1:
|
||||
type_name = "emc6d103";
|
||||
break;
|
||||
/*
|
||||
* Registers apparently missing in EMC6D103S/EMC6D103:A2
|
||||
* compared to EMC6D103:A0, EMC6D103:A1, and EMC6D102
|
||||
* (according to the data sheets), but used unconditionally
|
||||
* in the driver: 62[5:7], 6D[0:7], and 6E[0:7].
|
||||
* So skip EMC6D103S for now.
|
||||
case LM85_VERSTEP_EMC6D103S:
|
||||
type_name = "emc6d103s";
|
||||
break;
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
dev_dbg(&adapter->dev,
|
||||
|
@ -1267,6 +1275,10 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info)
|
|||
static void lm85_remove_files(struct i2c_client *client, struct lm85_data *data)
|
||||
{
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group);
|
||||
if (data->type != emc6d103s) {
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group_minctl);
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group_temp_off);
|
||||
}
|
||||
if (!data->has_vid5)
|
||||
sysfs_remove_group(&client->dev.kobj, &lm85_group_in4);
|
||||
if (data->type == emc6d100)
|
||||
|
@ -1295,6 +1307,7 @@ static int lm85_probe(struct i2c_client *client,
|
|||
case emc6d100:
|
||||
case emc6d102:
|
||||
case emc6d103:
|
||||
case emc6d103s:
|
||||
data->freq_map = adm1027_freq_map;
|
||||
break;
|
||||
default:
|
||||
|
@ -1312,6 +1325,17 @@ static int lm85_probe(struct i2c_client *client,
|
|||
if (err)
|
||||
goto err_kfree;
|
||||
|
||||
/* minctl and temp_off exist on all chips except emc6d103s */
|
||||
if (data->type != emc6d103s) {
|
||||
err = sysfs_create_group(&client->dev.kobj, &lm85_group_minctl);
|
||||
if (err)
|
||||
goto err_kfree;
|
||||
err = sysfs_create_group(&client->dev.kobj,
|
||||
&lm85_group_temp_off);
|
||||
if (err)
|
||||
goto err_kfree;
|
||||
}
|
||||
|
||||
/* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used
|
||||
as a sixth digital VID input rather than an analog input. */
|
||||
if (data->type == adt7463 || data->type == adt7468) {
|
||||
|
@ -1475,7 +1499,8 @@ static struct lm85_data *lm85_update_device(struct device *dev)
|
|||
/* More alarm bits */
|
||||
data->alarms |= lm85_read_value(client,
|
||||
EMC6D100_REG_ALARM3) << 16;
|
||||
} else if (data->type == emc6d102 || data->type == emc6d103) {
|
||||
} else if (data->type == emc6d102 || data->type == emc6d103 ||
|
||||
data->type == emc6d103s) {
|
||||
/* Have to read LSB bits after the MSB ones because
|
||||
the reading of the MSB bits has frozen the
|
||||
LSBs (backward from the ADM1027).
|
||||
|
@ -1560,17 +1585,19 @@ static struct lm85_data *lm85_update_device(struct device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
|
||||
data->autofan[0].min_off = (i & 0x20) != 0;
|
||||
data->autofan[1].min_off = (i & 0x40) != 0;
|
||||
data->autofan[2].min_off = (i & 0x80) != 0;
|
||||
if (data->type != emc6d103s) {
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_SPIKE1);
|
||||
data->autofan[0].min_off = (i & 0x20) != 0;
|
||||
data->autofan[1].min_off = (i & 0x40) != 0;
|
||||
data->autofan[2].min_off = (i & 0x80) != 0;
|
||||
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
|
||||
data->zone[0].hyst = i >> 4;
|
||||
data->zone[1].hyst = i & 0x0f;
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_HYST1);
|
||||
data->zone[0].hyst = i >> 4;
|
||||
data->zone[1].hyst = i & 0x0f;
|
||||
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
|
||||
data->zone[2].hyst = i >> 4;
|
||||
i = lm85_read_value(client, LM85_REG_AFAN_HYST2);
|
||||
data->zone[2].hyst = i >> 4;
|
||||
}
|
||||
|
||||
data->last_config = jiffies;
|
||||
} /* last_config */
|
||||
|
|
Loading…
Reference in a new issue