提交 310eb776 编写于 作者: L Linus Torvalds

Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pyll hwmon fixes from Guenter Roeck:
 "Two patches: Fix build warning in ads1015 driver, and fix bogus power
  values with current BIOSes in fam15h_power driver."

* tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (ads1015) Fix build warning
  hwmon: fam15h_power: fix bogus values with current BIOSes
...@@ -59,14 +59,11 @@ struct ads1015_data { ...@@ -59,14 +59,11 @@ struct ads1015_data {
struct ads1015_channel_data channel_data[ADS1015_CHANNELS]; struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
}; };
static int ads1015_read_value(struct i2c_client *client, unsigned int channel, static int ads1015_read_adc(struct i2c_client *client, unsigned int channel)
int *value)
{ {
u16 config; u16 config;
s16 conversion;
struct ads1015_data *data = i2c_get_clientdata(client); struct ads1015_data *data = i2c_get_clientdata(client);
unsigned int pga = data->channel_data[channel].pga; unsigned int pga = data->channel_data[channel].pga;
int fullscale;
unsigned int data_rate = data->channel_data[channel].data_rate; unsigned int data_rate = data->channel_data[channel].data_rate;
unsigned int conversion_time_ms; unsigned int conversion_time_ms;
int res; int res;
...@@ -78,7 +75,6 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel, ...@@ -78,7 +75,6 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
if (res < 0) if (res < 0)
goto err_unlock; goto err_unlock;
config = res; config = res;
fullscale = fullscale_table[pga];
conversion_time_ms = DIV_ROUND_UP(1000, data_rate_table[data_rate]); conversion_time_ms = DIV_ROUND_UP(1000, data_rate_table[data_rate]);
/* setup and start single conversion */ /* setup and start single conversion */
...@@ -105,33 +101,36 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel, ...@@ -105,33 +101,36 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
} }
res = i2c_smbus_read_word_swapped(client, ADS1015_CONVERSION); res = i2c_smbus_read_word_swapped(client, ADS1015_CONVERSION);
if (res < 0)
goto err_unlock;
conversion = res;
mutex_unlock(&data->update_lock);
*value = DIV_ROUND_CLOSEST(conversion * fullscale, 0x7ff0);
return 0;
err_unlock: err_unlock:
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return res; return res;
} }
static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel,
s16 reg)
{
struct ads1015_data *data = i2c_get_clientdata(client);
unsigned int pga = data->channel_data[channel].pga;
int fullscale = fullscale_table[pga];
return DIV_ROUND_CLOSEST(reg * fullscale, 0x7ff0);
}
/* sysfs callback function */ /* sysfs callback function */
static ssize_t show_in(struct device *dev, struct device_attribute *da, static ssize_t show_in(struct device *dev, struct device_attribute *da,
char *buf) char *buf)
{ {
struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
int in;
int res; int res;
int index = attr->index;
res = ads1015_read_value(client, attr->index, &in); res = ads1015_read_adc(client, index);
if (res < 0)
return res;
return (res < 0) ? res : sprintf(buf, "%d\n", in); return sprintf(buf, "%d\n", ads1015_reg_to_mv(client, index, res));
} }
static const struct sensor_device_attribute ads1015_in[] = { static const struct sensor_device_attribute ads1015_in[] = {
......
...@@ -122,6 +122,38 @@ static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4) ...@@ -122,6 +122,38 @@ static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4)
return true; return true;
} }
/*
* Newer BKDG versions have an updated recommendation on how to properly
* initialize the running average range (was: 0xE, now: 0x9). This avoids
* counter saturations resulting in bogus power readings.
* We correct this value ourselves to cope with older BIOSes.
*/
static void __devinit tweak_runavg_range(struct pci_dev *pdev)
{
u32 val;
const struct pci_device_id affected_device = {
PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) };
/*
* let this quirk apply only to the current version of the
* northbridge, since future versions may change the behavior
*/
if (!pci_match_id(&affected_device, pdev))
return;
pci_bus_read_config_dword(pdev->bus,
PCI_DEVFN(PCI_SLOT(pdev->devfn), 5),
REG_TDP_RUNNING_AVERAGE, &val);
if ((val & 0xf) != 0xe)
return;
val &= ~0xf;
val |= 0x9;
pci_bus_write_config_dword(pdev->bus,
PCI_DEVFN(PCI_SLOT(pdev->devfn), 5),
REG_TDP_RUNNING_AVERAGE, val);
}
static void __devinit fam15h_power_init_data(struct pci_dev *f4, static void __devinit fam15h_power_init_data(struct pci_dev *f4,
struct fam15h_power_data *data) struct fam15h_power_data *data)
{ {
...@@ -155,6 +187,13 @@ static int __devinit fam15h_power_probe(struct pci_dev *pdev, ...@@ -155,6 +187,13 @@ static int __devinit fam15h_power_probe(struct pci_dev *pdev,
struct device *dev; struct device *dev;
int err; int err;
/*
* though we ignore every other northbridge, we still have to
* do the tweaking on _each_ node in MCM processors as the counters
* are working hand-in-hand
*/
tweak_runavg_range(pdev);
if (!fam15h_power_is_internal_node0(pdev)) { if (!fam15h_power_is_internal_node0(pdev)) {
err = -ENODEV; err = -ENODEV;
goto exit; goto exit;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册