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

Pull hwmon updates from Jean Delvare:
 "We have support for the MCP3021, MC13892 and GMT G781, automatic fan
  speed control for LM63/LM64 chips, and a few clean-ups."

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  hwmon: Add MCP3021 ADC driver
  hwmon: (mc13783-adc) Add support for the MC13892 PMIC
  hwmon: (mc13783-adc) Remove space before tab
  hwmon: (lm63) Let the user adjust the lookup table
  hwmon: (lm63) Make fan speed control strategy changeable
  hwmon: (lm63) Reorganize the code
  hwmon: (lm90) Restore original configuration if probe function fails
  hwmon: (lm90) Add support for GMT G781
  hwmon: (lm90) Fix multi-line comments
  hwmon: (w83795) Fix multi-line comments
  hwmon: (w83795) Unconditionally support manual fan speed control
  hwmon: (fam15h_power) Increase output resolution
  hwmon: (fam15h_power) Correct sign extension of running_avg_capture
This commit is contained in:
Linus Torvalds 2012-03-23 14:37:52 -07:00
commit f37ab0fba2
11 changed files with 827 additions and 380 deletions

View File

@ -118,6 +118,10 @@ Supported chips:
Addresses scanned: I2C 0x48 through 0x4F
Datasheet: Publicly available at NXP website
http://ics.nxp.com/products/interface/datasheet/sa56004x.pdf
* GMT G781
Prefix: 'g781'
Addresses scanned: I2C 0x4c, 0x4d
Datasheet: Not publicly available from GMT
Author: Jean Delvare <khali@linux-fr.org>

View File

@ -3,8 +3,11 @@ Kernel driver mc13783-adc
Supported chips:
* Freescale Atlas MC13783
Prefix: 'mc13783_adc'
Prefix: 'mc13783'
Datasheet: http://www.freescale.com/files/rf_if/doc/data_sheet/MC13783.pdf?fsrch=1
* Freescale Atlas MC13892
Prefix: 'mc13892'
Datasheet: http://cache.freescale.com/files/analog/doc/data_sheet/MC13892.pdf?fsrch=1&sr=1
Authors:
Sascha Hauer <s.hauer@pengutronix.de>
@ -13,20 +16,21 @@ Authors:
Description
-----------
The Freescale MC13783 is a Power Management and Audio Circuit. Among
other things it contains a 10-bit A/D converter. The converter has 16
channels which can be used in different modes.
The A/D converter has a resolution of 2.25mV. Channels 0-4 have
a dedicated meaning with chip internal scaling applied. Channels 5-7
can be used as general purpose inputs or alternatively in a dedicated
mode. Channels 12-15 are occupied by the touchscreen if it's active.
The Freescale MC13783 and MC13892 are Power Management and Audio Circuits.
Among other things they contain a 10-bit A/D converter. The converter has 16
(MC13783) resp. 12 (MC13892) channels which can be used in different modes. The
A/D converter has a resolution of 2.25mV.
Currently the driver only supports channels 2 and 5-15 with no alternative
modes for channels 5-7.
Some channels can be used as General Purpose inputs or in a dedicated mode with
a chip internal scaling applied .
See this table for the meaning of the different channels and their chip
internal scaling:
Currently the driver only supports the Application Supply channel (BP / BPSNS),
the General Purpose inputs and touchscreen.
See the following tables for the meaning of the different channels and their
chip internal scaling:
MC13783:
Channel Signal Input Range Scaling
-------------------------------------------------------------------------------
0 Battery Voltage (BATT) 2.50 - 4.65V -2.40V
@ -34,7 +38,7 @@ Channel Signal Input Range Scaling
2 Application Supply (BP) 2.50 - 4.65V -2.40V
3 Charger Voltage (CHRGRAW) 0 - 10V / /5
0 - 20V /10
4 Charger Current (CHRGISNSP-CHRGISNSN) -0.25V - 0.25V x4
4 Charger Current (CHRGISNSP-CHRGISNSN) -0.25 - 0.25V x4
5 General Purpose ADIN5 / Battery Pack Thermistor 0 - 2.30V No
6 General Purpose ADIN6 / Backup Voltage (LICELL) 0 - 2.30V / No /
1.50 - 3.50V -1.20V
@ -48,3 +52,23 @@ Channel Signal Input Range Scaling
13 General Purpose TSX2 / Touchscreen X-plate 2 0 - 2.30V No
14 General Purpose TSY1 / Touchscreen Y-plate 1 0 - 2.30V No
15 General Purpose TSY2 / Touchscreen Y-plate 2 0 - 2.30V No
MC13892:
Channel Signal Input Range Scaling
-------------------------------------------------------------------------------
0 Battery Voltage (BATT) 0 - 4.8V /2
1 Battery Current (BATT - BATTISNSCC) -60 - 60 mV x20
2 Application Supply (BPSNS) 0 - 4.8V /2
3 Charger Voltage (CHRGRAW) 0 - 12V / /5
0 - 20V /10
4 Charger Current (CHRGISNS-BPSNS) / -0.3 - 0.3V / x4 /
Touchscreen X-plate 1 0 - 2.4V No
5 General Purpose ADIN5 / Battery Pack Thermistor 0 - 2.4V No
6 General Purpose ADIN6 / Backup Voltage (LICELL) 0 - 2.4V / No
Backup Voltage (LICELL) 0 - 3.6V x2/3
7 General Purpose ADIN7 / UID / Die Temperature 0 - 2.4V / No /
0 - 4.8V /2
12 General Purpose TSX1 / Touchscreen X-plate 1 0 - 2.4V No
13 General Purpose TSX2 / Touchscreen X-plate 2 0 - 2.4V No
14 General Purpose TSY1 / Touchscreen Y-plate 1 0 - 2.4V No
15 General Purpose TSY2 / Touchscreen Y-plate 2 0 - 2.4V No

View File

@ -0,0 +1,22 @@
Kernel driver MCP3021
======================
Supported chips:
* Microchip Technology MCP3021
Prefix: 'mcp3021'
Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/21805a.pdf
Author: Mingkai Hu
Description
-----------
This driver implements support for the Microchip Technology MCP3021 chip.
The Microchip Technology Inc. MCP3021 is a successive approximation A/D
converter (ADC) with 10-bit resolution.
This device provides one single-ended input with very low power consumption.
Communication to the MCP3021 is performed using a 2-wire I2C compatible
interface. Standard (100 kHz) and Fast (400 kHz) I2C modes are available.
The default I2C device address is 0x4d (contact the Microchip factory for
additional address options).

View File

@ -648,7 +648,8 @@ config SENSORS_LM90
LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A,
Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008,
Winbond/Nuvoton W83L771W/G/AWG/ASG and Philips SA56004 sensor chips.
Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, and GMT G781
sensor chips.
This driver can also be built as a module. If so, the module
will be called lm90.
@ -812,6 +813,16 @@ config SENSORS_MAX6650
This driver can also be built as a module. If so, the module
will be called max6650.
config SENSORS_MCP3021
tristate "Microchip MCP3021"
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the MCP3021 chip
that is a A/D converter (ADC) with 10-bit resolution.
This driver can also be built as a module. If so, the module
will be called mcp3021.
config SENSORS_NTC_THERMISTOR
tristate "NTC thermistor support"
depends on EXPERIMENTAL
@ -1229,18 +1240,19 @@ config SENSORS_W83795
depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the Winbond W83795G and
W83795ADG hardware monitoring chip.
W83795ADG hardware monitoring chip, including manual fan speed
control.
This driver can also be built as a module. If so, the module
will be called w83795.
config SENSORS_W83795_FANCTRL
boolean "Include fan control support (DANGEROUS)"
boolean "Include automatic fan control support (DANGEROUS)"
depends on SENSORS_W83795 && EXPERIMENTAL
default n
help
If you say yes here, support for the both manual and automatic
fan control features will be included in the driver.
If you say yes here, support for automatic fan speed control
will be included in the driver.
This part of the code wasn't carefully reviewed and tested yet,
so enabling this option is strongly discouraged on production
@ -1358,10 +1370,10 @@ config SENSORS_APPLESMC
the awesome power of applesmc.
config SENSORS_MC13783_ADC
tristate "Freescale MC13783 ADC"
depends on MFD_MC13783
tristate "Freescale MC13783/MC13892 ADC"
depends on MFD_MC13XXX
help
Support for the A/D converter on MC13783 PMIC.
Support for the A/D converter on MC13783 and MC13892 PMIC.
if ACPI

View File

@ -95,6 +95,7 @@ obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o

View File

@ -60,15 +60,15 @@ static ssize_t show_power(struct device *dev,
pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
REG_TDP_RUNNING_AVERAGE, &val);
running_avg_capture = (val >> 4) & 0x3fffff;
running_avg_capture = sign_extend32(running_avg_capture, 22);
running_avg_range = val & 0xf;
running_avg_capture = sign_extend32(running_avg_capture, 21);
running_avg_range = (val & 0xf) + 1;
pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
REG_TDP_LIMIT3, &val);
tdp_limit = val >> 16;
curr_pwr_watts = tdp_limit + data->base_tdp -
(s32)(running_avg_capture >> (running_avg_range + 1));
curr_pwr_watts = (tdp_limit + data->base_tdp) << running_avg_range;
curr_pwr_watts -= running_avg_capture;
curr_pwr_watts *= data->tdp_to_watts;
/*
@ -78,7 +78,7 @@ static ssize_t show_power(struct device *dev,
* scaling factor 1/(2^16). For conversion we use
* (10^6)/(2^16) = 15625/(2^10)
*/
curr_pwr_watts = (curr_pwr_watts * 15625) >> 10;
curr_pwr_watts = (curr_pwr_watts * 15625) >> (10 + running_avg_range);
return sprintf(buf, "%u\n", (unsigned int) curr_pwr_watts);
}
static DEVICE_ATTR(power1_input, S_IRUGO, show_power, NULL);

View File

@ -148,45 +148,8 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
#define UPDATE_INTERVAL(max, rate) \
((1000 << (LM63_MAX_CONVRATE - (rate))) / (max))
/*
* Functions declaration
*/
static int lm63_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static int lm63_remove(struct i2c_client *client);
static struct lm63_data *lm63_update_device(struct device *dev);
static int lm63_detect(struct i2c_client *client, struct i2c_board_info *info);
static void lm63_init_client(struct i2c_client *client);
enum chips { lm63, lm64, lm96163 };
/*
* Driver data (common to all clients)
*/
static const struct i2c_device_id lm63_id[] = {
{ "lm63", lm63 },
{ "lm64", lm64 },
{ "lm96163", lm96163 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm63_id);
static struct i2c_driver lm63_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm63",
},
.probe = lm63_probe,
.remove = lm63_remove,
.id_table = lm63_id,
.detect = lm63_detect,
.address_list = normal_i2c,
};
/*
* Client data (each client gets its own)
*/
@ -242,6 +205,145 @@ static inline int lut_temp_from_reg(struct lm63_data *data, int nr)
return data->temp8[nr] * (data->lut_temp_highres ? 500 : 1000);
}
static inline int lut_temp_to_reg(struct lm63_data *data, long val)
{
val -= data->temp2_offset;
if (data->lut_temp_highres)
return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127500), 500);
else
return DIV_ROUND_CLOSEST(SENSORS_LIMIT(val, 0, 127000), 1000);
}
/*
* Update the lookup table register cache.
* client->update_lock must be held when calling this function.
*/
static void lm63_update_lut(struct i2c_client *client)
{
struct lm63_data *data = i2c_get_clientdata(client);
int i;
if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
!data->lut_valid) {
for (i = 0; i < data->lut_size; i++) {
data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
LM63_REG_LUT_PWM(i));
data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
LM63_REG_LUT_TEMP(i));
}
data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
LM63_REG_LUT_TEMP_HYST);
data->lut_last_updated = jiffies;
data->lut_valid = 1;
}
}
static struct lm63_data *lm63_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
unsigned long next_update;
mutex_lock(&data->update_lock);
next_update = data->last_updated
+ msecs_to_jiffies(data->update_interval) + 1;
if (time_after(jiffies, next_update) || !data->valid) {
if (data->config & 0x04) { /* tachometer enabled */
/* order matters for fan1_input */
data->fan[0] = i2c_smbus_read_byte_data(client,
LM63_REG_TACH_COUNT_LSB) & 0xFC;
data->fan[0] |= i2c_smbus_read_byte_data(client,
LM63_REG_TACH_COUNT_MSB) << 8;
data->fan[1] = (i2c_smbus_read_byte_data(client,
LM63_REG_TACH_LIMIT_LSB) & 0xFC)
| (i2c_smbus_read_byte_data(client,
LM63_REG_TACH_LIMIT_MSB) << 8);
}
data->pwm1_freq = i2c_smbus_read_byte_data(client,
LM63_REG_PWM_FREQ);
if (data->pwm1_freq == 0)
data->pwm1_freq = 1;
data->pwm1[0] = i2c_smbus_read_byte_data(client,
LM63_REG_PWM_VALUE);
data->temp8[0] = i2c_smbus_read_byte_data(client,
LM63_REG_LOCAL_TEMP);
data->temp8[1] = i2c_smbus_read_byte_data(client,
LM63_REG_LOCAL_HIGH);
/* order matters for temp2_input */
data->temp11[0] = i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_TEMP_MSB) << 8;
data->temp11[0] |= i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_TEMP_LSB);
data->temp11[1] = (i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_LOW_MSB) << 8)
| i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_LOW_LSB);
data->temp11[2] = (i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_HIGH_MSB) << 8)
| i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_HIGH_LSB);
data->temp11[3] = (i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_OFFSET_MSB) << 8)
| i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_OFFSET_LSB);
if (data->kind == lm96163)
data->temp11u = (i2c_smbus_read_byte_data(client,
LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
| i2c_smbus_read_byte_data(client,
LM96163_REG_REMOTE_TEMP_U_LSB);
data->temp8[2] = i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_TCRIT);
data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_TCRIT_HYST);
data->alarms = i2c_smbus_read_byte_data(client,
LM63_REG_ALERT_STATUS) & 0x7F;
data->last_updated = jiffies;
data->valid = 1;
}
lm63_update_lut(client);
mutex_unlock(&data->update_lock);
return data;
}
/*
* Trip points in the lookup table should be in ascending order for both
* temperatures and PWM output values.
*/
static int lm63_lut_looks_bad(struct i2c_client *client)
{
struct lm63_data *data = i2c_get_clientdata(client);
int i;
mutex_lock(&data->update_lock);
lm63_update_lut(client);
for (i = 1; i < data->lut_size; i++) {
if (data->pwm1[1 + i - 1] > data->pwm1[1 + i]
|| data->temp8[3 + i - 1] > data->temp8[3 + i]) {
dev_warn(&client->dev,
"Lookup table doesn't look sane (check entries %d and %d)\n",
i, i + 1);
break;
}
}
mutex_unlock(&data->update_lock);
return i == data->lut_size ? 0 : 1;
}
/*
* Sysfs callback functions and files
*/
@ -294,13 +396,16 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
return sprintf(buf, "%d\n", pwm);
}
static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
int nr = attr->index;
unsigned long val;
int err;
u8 reg;
if (!(data->config_fan & 0x20)) /* register is read-only */
return -EPERM;
@ -309,11 +414,13 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *dummy,
if (err)
return err;
reg = nr ? LM63_REG_LUT_PWM(nr - 1) : LM63_REG_PWM_VALUE;
val = SENSORS_LIMIT(val, 0, 255);
mutex_lock(&data->update_lock);
data->pwm1[0] = data->pwm_highres ? val :
data->pwm1[nr] = data->pwm_highres ? val :
(val * data->pwm1_freq * 2 + 127) / 255;
i2c_smbus_write_byte_data(client, LM63_REG_PWM_VALUE, data->pwm1[0]);
i2c_smbus_write_byte_data(client, reg, data->pwm1[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@ -325,6 +432,41 @@ static ssize_t show_pwm1_enable(struct device *dev,
return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2);
}
static ssize_t set_pwm1_enable(struct device *dev,
struct device_attribute *dummy,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
unsigned long val;
int err;
err = kstrtoul(buf, 10, &val);
if (err)
return err;
if (val < 1 || val > 2)
return -EINVAL;
/*
* Only let the user switch to automatic mode if the lookup table
* looks sane.
*/
if (val == 2 && lm63_lut_looks_bad(client))
return -EPERM;
mutex_lock(&data->update_lock);
data->config_fan = i2c_smbus_read_byte_data(client,
LM63_REG_CONFIG_FAN);
if (val == 1)
data->config_fan |= 0x20;
else
data->config_fan &= ~0x20;
i2c_smbus_write_byte_data(client, LM63_REG_CONFIG_FAN,
data->config_fan);
mutex_unlock(&data->update_lock);
return count;
}
/*
* There are 8bit registers for both local(temp1) and remote(temp2) sensor.
* For remote sensor registers temp2_offset has to be considered,
@ -367,23 +509,31 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr,
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
int nr = attr->index;
int reg = nr == 2 ? LM63_REG_REMOTE_TCRIT : LM63_REG_LOCAL_HIGH;
long val;
int err;
int temp;
u8 reg;
err = kstrtol(buf, 10, &val);
if (err)
return err;
mutex_lock(&data->update_lock);
if (nr == 2) {
switch (nr) {
case 2:
reg = LM63_REG_REMOTE_TCRIT;
if (data->remote_unsigned)
temp = TEMP8U_TO_REG(val - data->temp2_offset);
else
temp = TEMP8_TO_REG(val - data->temp2_offset);
} else {
break;
case 1:
reg = LM63_REG_LOCAL_HIGH;
temp = TEMP8_TO_REG(val);
break;
default: /* lookup table */
reg = LM63_REG_LUT_TEMP(nr - 3);
temp = lut_temp_to_reg(data, val);
}
data->temp8[nr] = temp;
i2c_smbus_write_byte_data(client, reg, temp);
@ -613,65 +763,78 @@ static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
set_fan, 1);
static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
static DEVICE_ATTR(pwm1_enable, S_IRUGO, show_pwm1_enable, NULL);
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, show_pwm1, NULL, 1);
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IRUGO,
show_lut_temp, NULL, 3);
static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
show_pwm1_enable, set_pwm1_enable);
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 1);
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 3);
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 3);
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IRUGO, show_pwm1, NULL, 2);
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO,
show_lut_temp, NULL, 4);
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 2);
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 4);
static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 4);
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, show_pwm1, NULL, 3);
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IRUGO,
show_lut_temp, NULL, 5);
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 3);
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 5);
static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 5);
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IRUGO, show_pwm1, NULL, 4);
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IRUGO,
show_lut_temp, NULL, 6);
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 4);
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 6);
static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 6);
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IRUGO, show_pwm1, NULL, 5);
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IRUGO,
show_lut_temp, NULL, 7);
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 5);
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 7);
static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 7);
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IRUGO, show_pwm1, NULL, 6);
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IRUGO,
show_lut_temp, NULL, 8);
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 6);
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 8);
static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 8);
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IRUGO, show_pwm1, NULL, 7);
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IRUGO,
show_lut_temp, NULL, 9);
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 7);
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 9);
static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 9);
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IRUGO, show_pwm1, NULL, 8);
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IRUGO,
show_lut_temp, NULL, 10);
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 8);
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 10);
static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 10);
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IRUGO, show_pwm1, NULL, 9);
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IRUGO,
show_lut_temp, NULL, 11);
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 9);
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 11);
static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 11);
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IRUGO, show_pwm1, NULL, 10);
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IRUGO,
show_lut_temp, NULL, 12);
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 10);
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 12);
static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 12);
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IRUGO, show_pwm1, NULL, 11);
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IRUGO,
show_lut_temp, NULL, 13);
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 11);
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 13);
static SENSOR_DEVICE_ATTR(pwm1_auto_point11_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 13);
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IRUGO, show_pwm1, NULL, 12);
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IRUGO,
show_lut_temp, NULL, 14);
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_pwm, S_IWUSR | S_IRUGO,
show_pwm1, set_pwm1, 12);
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp, S_IWUSR | S_IRUGO,
show_lut_temp, set_temp8, 14);
static SENSOR_DEVICE_ATTR(pwm1_auto_point12_temp_hyst, S_IRUGO,
show_lut_temp_hyst, NULL, 14);
@ -817,28 +980,25 @@ static const struct attribute_group lm63_group_fan1 = {
*/
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm63_detect(struct i2c_client *new_client,
static int lm63_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = new_client->adapter;
struct i2c_adapter *adapter = client->adapter;
u8 man_id, chip_id, reg_config1, reg_config2;
u8 reg_alert_status, reg_alert_mask;
int address = new_client->addr;
int address = client->addr;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
man_id = i2c_smbus_read_byte_data(new_client, LM63_REG_MAN_ID);
chip_id = i2c_smbus_read_byte_data(new_client, LM63_REG_CHIP_ID);
man_id = i2c_smbus_read_byte_data(client, LM63_REG_MAN_ID);
chip_id = i2c_smbus_read_byte_data(client, LM63_REG_CHIP_ID);
reg_config1 = i2c_smbus_read_byte_data(new_client,
LM63_REG_CONFIG1);
reg_config2 = i2c_smbus_read_byte_data(new_client,
LM63_REG_CONFIG2);
reg_alert_status = i2c_smbus_read_byte_data(new_client,
reg_config1 = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG1);
reg_config2 = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG2);
reg_alert_status = i2c_smbus_read_byte_data(client,
LM63_REG_ALERT_STATUS);
reg_alert_mask = i2c_smbus_read_byte_data(new_client,
LM63_REG_ALERT_MASK);
reg_alert_mask = i2c_smbus_read_byte_data(client, LM63_REG_ALERT_MASK);
if (man_id != 0x01 /* National Semiconductor */
|| (reg_config1 & 0x18) != 0x00
@ -863,74 +1023,6 @@ static int lm63_detect(struct i2c_client *new_client,
return 0;
}
static int lm63_probe(struct i2c_client *new_client,
const struct i2c_device_id *id)
{
struct lm63_data *data;
int err;
data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit;
}
i2c_set_clientdata(new_client, data);
data->valid = 0;
mutex_init(&data->update_lock);
/* Set the device type */
data->kind = id->driver_data;
if (data->kind == lm64)
data->temp2_offset = 16000;
/* Initialize chip */
lm63_init_client(new_client);
/* Register sysfs hooks */
err = sysfs_create_group(&new_client->dev.kobj, &lm63_group);
if (err)
goto exit_free;
if (data->config & 0x04) { /* tachometer enabled */
err = sysfs_create_group(&new_client->dev.kobj,
&lm63_group_fan1);
if (err)
goto exit_remove_files;
}
if (data->kind == lm96163) {
err = device_create_file(&new_client->dev,
&dev_attr_temp2_type);
if (err)
goto exit_remove_files;
err = sysfs_create_group(&new_client->dev.kobj,
&lm63_group_extra_lut);
if (err)
goto exit_remove_files;
}
data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
return 0;
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
if (data->kind == lm96163) {
device_remove_file(&new_client->dev, &dev_attr_temp2_type);
sysfs_remove_group(&new_client->dev.kobj,
&lm63_group_extra_lut);
}
exit_free:
kfree(data);
exit:
return err;
}
/*
* Ideally we shouldn't have to initialize anything, since the BIOS
* should have taken care of everything
@ -1010,6 +1102,71 @@ static void lm63_init_client(struct i2c_client *client)
(data->config_fan & 0x20) ? "manual" : "auto");
}
static int lm63_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct lm63_data *data;
int err;
data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
data->valid = 0;
mutex_init(&data->update_lock);
/* Set the device type */
data->kind = id->driver_data;
if (data->kind == lm64)
data->temp2_offset = 16000;
/* Initialize chip */
lm63_init_client(client);
/* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &lm63_group);
if (err)
goto exit_free;
if (data->config & 0x04) { /* tachometer enabled */
err = sysfs_create_group(&client->dev.kobj, &lm63_group_fan1);
if (err)
goto exit_remove_files;
}
if (data->kind == lm96163) {
err = device_create_file(&client->dev, &dev_attr_temp2_type);
if (err)
goto exit_remove_files;
err = sysfs_create_group(&client->dev.kobj,
&lm63_group_extra_lut);
if (err)
goto exit_remove_files;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
return 0;
exit_remove_files:
sysfs_remove_group(&client->dev.kobj, &lm63_group);
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
if (data->kind == lm96163) {
device_remove_file(&client->dev, &dev_attr_temp2_type);
sysfs_remove_group(&client->dev.kobj, &lm63_group_extra_lut);
}
exit_free:
kfree(data);
exit:
return err;
}
static int lm63_remove(struct i2c_client *client)
{
struct lm63_data *data = i2c_get_clientdata(client);
@ -1026,98 +1183,29 @@ static int lm63_remove(struct i2c_client *client)
return 0;
}
static struct lm63_data *lm63_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct lm63_data *data = i2c_get_clientdata(client);
unsigned long next_update;
int i;
/*
* Driver data (common to all clients)
*/
mutex_lock(&data->update_lock);
static const struct i2c_device_id lm63_id[] = {
{ "lm63", lm63 },
{ "lm64", lm64 },
{ "lm96163", lm96163 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm63_id);
next_update = data->last_updated
+ msecs_to_jiffies(data->update_interval) + 1;
if (time_after(jiffies, next_update) || !data->valid) {
if (data->config & 0x04) { /* tachometer enabled */
/* order matters for fan1_input */
data->fan[0] = i2c_smbus_read_byte_data(client,
LM63_REG_TACH_COUNT_LSB) & 0xFC;
data->fan[0] |= i2c_smbus_read_byte_data(client,
LM63_REG_TACH_COUNT_MSB) << 8;
data->fan[1] = (i2c_smbus_read_byte_data(client,
LM63_REG_TACH_LIMIT_LSB) & 0xFC)
| (i2c_smbus_read_byte_data(client,
LM63_REG_TACH_LIMIT_MSB) << 8);
}
data->pwm1_freq = i2c_smbus_read_byte_data(client,
LM63_REG_PWM_FREQ);
if (data->pwm1_freq == 0)
data->pwm1_freq = 1;
data->pwm1[0] = i2c_smbus_read_byte_data(client,
LM63_REG_PWM_VALUE);
data->temp8[0] = i2c_smbus_read_byte_data(client,
LM63_REG_LOCAL_TEMP);
data->temp8[1] = i2c_smbus_read_byte_data(client,
LM63_REG_LOCAL_HIGH);
/* order matters for temp2_input */
data->temp11[0] = i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_TEMP_MSB) << 8;
data->temp11[0] |= i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_TEMP_LSB);
data->temp11[1] = (i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_LOW_MSB) << 8)
| i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_LOW_LSB);
data->temp11[2] = (i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_HIGH_MSB) << 8)
| i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_HIGH_LSB);
data->temp11[3] = (i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_OFFSET_MSB) << 8)
| i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_OFFSET_LSB);
if (data->kind == lm96163)
data->temp11u = (i2c_smbus_read_byte_data(client,
LM96163_REG_REMOTE_TEMP_U_MSB) << 8)
| i2c_smbus_read_byte_data(client,
LM96163_REG_REMOTE_TEMP_U_LSB);
data->temp8[2] = i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_TCRIT);
data->temp2_crit_hyst = i2c_smbus_read_byte_data(client,
LM63_REG_REMOTE_TCRIT_HYST);
data->alarms = i2c_smbus_read_byte_data(client,
LM63_REG_ALERT_STATUS) & 0x7F;
data->last_updated = jiffies;
data->valid = 1;
}
if (time_after(jiffies, data->lut_last_updated + 5 * HZ) ||
!data->lut_valid) {
for (i = 0; i < data->lut_size; i++) {
data->pwm1[1 + i] = i2c_smbus_read_byte_data(client,
LM63_REG_LUT_PWM(i));
data->temp8[3 + i] = i2c_smbus_read_byte_data(client,
LM63_REG_LUT_TEMP(i));
}
data->lut_temp_hyst = i2c_smbus_read_byte_data(client,
LM63_REG_LUT_TEMP_HYST);
data->lut_last_updated = jiffies;
data->lut_valid = 1;
}
mutex_unlock(&data->update_lock);
return data;
}
static struct i2c_driver lm63_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm63",
},
.probe = lm63_probe,
.remove = lm63_remove,
.id_table = lm63_id,
.detect = lm63_detect,
.address_list = normal_i2c,
};
module_i2c_driver(lm63_driver);

View File

@ -57,6 +57,9 @@
* This driver also supports the SA56004 from Philips. This device is
* pin-compatible with the LM86, the ED/EDP parts are also address-compatible.
*
* This driver also supports the G781 from GMT. This device is compatible
* with the ADM1032.
*
* Since the LM90 was the first chipset supported by this driver, most
* comments will refer to this chipset, but are actually general and
* concern all supported chipsets, unless mentioned otherwise.
@ -107,7 +110,7 @@ static const unsigned short normal_i2c[] = {
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
max6646, w83l771, max6696, sa56004 };
max6646, w83l771, max6696, sa56004, g781 };
/*
* The LM90 registers
@ -184,6 +187,7 @@ static const struct i2c_device_id lm90_id[] = {
{ "adm1032", adm1032 },
{ "adt7461", adt7461 },
{ "adt7461a", adt7461 },
{ "g781", g781 },
{ "lm90", lm90 },
{ "lm86", lm86 },
{ "lm89", lm86 },
@ -229,6 +233,12 @@ static const struct lm90_params lm90_params[] = {
.alert_alarms = 0x7c,
.max_convrate = 10,
},
[g781] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
| LM90_HAVE_BROKEN_ALERT,
.alert_alarms = 0x7c,
.max_convrate = 8,
},
[lm86] = {
.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT,
.alert_alarms = 0x7b,
@ -308,22 +318,24 @@ struct lm90_data {
/* registers values */
s8 temp8[8]; /* 0: local low limit
1: local high limit
2: local critical limit
3: remote critical limit
4: local emergency limit (max6659 and max6695/96)
5: remote emergency limit (max6659 and max6695/96)
6: remote 2 critical limit (max6695/96 only)
7: remote 2 emergency limit (max6695/96 only) */
* 1: local high limit
* 2: local critical limit
* 3: remote critical limit
* 4: local emergency limit (max6659 and max6695/96)
* 5: remote emergency limit (max6659 and max6695/96)
* 6: remote 2 critical limit (max6695/96 only)
* 7: remote 2 emergency limit (max6695/96 only)
*/
s16 temp11[8]; /* 0: remote input
1: remote low limit
2: remote high limit
3: remote offset (except max6646, max6657/58/59,
and max6695/96)
4: local input
5: remote 2 input (max6695/96 only)
6: remote 2 low limit (max6695/96 only)
7: remote 2 high limit (ma6695/96 only) */
* 1: remote low limit
* 2: remote high limit
* 3: remote offset (except max6646, max6657/58/59,
* and max6695/96)
* 4: local input
* 5: remote 2 input (max6695/96 only)
* 6: remote 2 low limit (max6695/96 only)
* 7: remote 2 high limit (max6695/96 only)
*/
u8 temp_hyst;
u16 alarms; /* bitvector (upper 8 bits for max6695/96) */
};
@ -533,8 +545,10 @@ static struct lm90_data *lm90_update_device(struct device *dev)
data->alarms |= alarms << 8;
}
/* Re-enable ALERT# output if it was originally enabled and
* relevant alarms are all clear */
/*
* Re-enable ALERT# output if it was originally enabled and
* relevant alarms are all clear
*/
if ((data->config_orig & 0x80) == 0
&& (data->alarms & data->alert_alarms) == 0) {
u8 config;
@ -1162,8 +1176,10 @@ static int lm90_detect(struct i2c_client *client,
&& (config1 & 0x3F) == 0x00
&& convrate <= 0x0A) {
name = "adm1032";
/* The ADM1032 supports PEC, but only if combined
transactions are not used. */
/*
* The ADM1032 supports PEC, but only if combined
* transactions are not used.
*/
if (i2c_check_functionality(adapter,
I2C_FUNC_SMBUS_BYTE))
info->flags |= I2C_CLIENT_PEC;
@ -1283,6 +1299,13 @@ static int lm90_detect(struct i2c_client *client,
&& convrate <= 0x09) {
name = "sa56004";
}
} else
if ((address == 0x4C || address == 0x4D)
&& man_id == 0x47) { /* GMT */
if (chip_id == 0x01 /* G781 */
&& (config1 & 0x3F) == 0x00
&& convrate <= 0x08)
name = "g781";
}
if (!name) { /* identification failed */
@ -1313,6 +1336,15 @@ static void lm90_remove_files(struct i2c_client *client, struct lm90_data *data)
sysfs_remove_group(&dev->kobj, &lm90_group);
}
static void lm90_restore_conf(struct i2c_client *client, struct lm90_data *data)
{
/* Restore initial configuration */
i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
data->convrate_orig);
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
data->config_orig);
}
static void lm90_init_client(struct i2c_client *client)
{
u8 config, convrate;
@ -1382,8 +1414,10 @@ static int lm90_probe(struct i2c_client *client,
client->flags &= ~I2C_CLIENT_PEC;
}
/* Different devices have different alarm bits triggering the
* ALERT# output */
/*
* Different devices have different alarm bits triggering the
* ALERT# output
*/
data->alert_alarms = lm90_params[data->kind].alert_alarms;
/* Set chip capabilities */
@ -1399,7 +1433,7 @@ static int lm90_probe(struct i2c_client *client,
/* Register sysfs hooks */
err = sysfs_create_group(&dev->kobj, &lm90_group);
if (err)
goto exit_free;
goto exit_restore;
if (client->flags & I2C_CLIENT_PEC) {
err = device_create_file(dev, &dev_attr_pec);
if (err)
@ -1438,7 +1472,8 @@ static int lm90_probe(struct i2c_client *client,
exit_remove_files:
lm90_remove_files(client, data);
exit_free:
exit_restore:
lm90_restore_conf(client, data);
kfree(data);
exit:
return err;
@ -1450,12 +1485,7 @@ static int lm90_remove(struct i2c_client *client)
hwmon_device_unregister(data->hwmon_dev);
lm90_remove_files(client, data);
/* Restore initial configuration */
i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
data->convrate_orig);
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
data->config_orig);
lm90_restore_conf(client, data);
kfree(data);
return 0;
@ -1488,9 +1518,11 @@ static void lm90_alert(struct i2c_client *client, unsigned int flag)
dev_warn(&client->dev,
"temp%d out of range, please check!\n", 3);
/* Disable ALERT# output, because these chips don't implement
SMBus alert correctly; they should only hold the alert line
low briefly. */
/*
* Disable ALERT# output, because these chips don't implement
* SMBus alert correctly; they should only hold the alert line
* low briefly.
*/
if ((data->flags & LM90_HAVE_BROKEN_ALERT)
&& (alarms & data->alert_alarms)) {
dev_dbg(&client->dev, "Disabling ALERT#\n");

View File

@ -1,5 +1,5 @@
/*
* Driver for the Freescale Semiconductor MC13783 adc.
* Driver for the ADC on Freescale Semiconductor MC13783 and MC13892 PMICs.
*
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
* Copyright (C) 2009 Sascha Hauer, Pengutronix
@ -18,7 +18,7 @@
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/mfd/mc13783.h>
#include <linux/mfd/mc13xxx.h>
#include <linux/platform_device.h>
#include <linux/hwmon-sysfs.h>
#include <linux/kernel.h>
@ -28,24 +28,30 @@
#include <linux/init.h>
#include <linux/err.h>
#define MC13783_ADC_NAME "mc13783-adc"
#define DRIVER_NAME "mc13783-adc"
/* platform device id driver data */
#define MC13783_ADC_16CHANS 1
#define MC13783_ADC_BPDIV2 2
struct mc13783_adc_priv {
struct mc13xxx *mc13xxx;
struct device *hwmon_dev;
char name[10];
};
static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{
return sprintf(buf, "mc13783_adc\n");
struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", priv->name);
}
static int mc13783_adc_read(struct device *dev,
struct device_attribute *devattr, unsigned int *val)
{
struct platform_device *pdev = to_platform_device(dev);
struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
struct mc13783_adc_priv *priv = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
unsigned int channel = attr->index;
unsigned int sample[4];
@ -68,16 +74,21 @@ static ssize_t mc13783_adc_read_bp(struct device *dev,
struct device_attribute *devattr, char *buf)
{
unsigned val;
struct platform_device *pdev = to_platform_device(dev);
kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
int ret = mc13783_adc_read(dev, devattr, &val);
if (ret)
return ret;
/*
* BP (channel 2) reports with offset 2.4V to the actual value to fit
* the input range of the ADC. unit = 2.25mV = 9/4 mV.
*/
val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
if (driver_data & MC13783_ADC_BPDIV2)
val = DIV_ROUND_CLOSEST(val * 9, 2);
else
/*
* BP (channel 2) reports with offset 2.4V to the actual value
* to fit the input range of the ADC. unit = 2.25mV = 9/4 mV.
*/
val = DIV_ROUND_CLOSEST(val * 9, 4) + 2400;
return sprintf(buf, "%u\n", val);
}
@ -114,12 +125,21 @@ static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, mc13783_adc_read_gp, NULL, 13);
static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, mc13783_adc_read_gp, NULL, 14);
static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, mc13783_adc_read_gp, NULL, 15);
static struct attribute *mc13783_attr[] = {
static struct attribute *mc13783_attr_base[] = {
&dev_attr_name.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in6_input.dev_attr.attr,
&sensor_dev_attr_in7_input.dev_attr.attr,
NULL
};
static const struct attribute_group mc13783_group_base = {
.attrs = mc13783_attr_base,
};
/* these are only used if MC13783_ADC_16CHANS is provided in driver data */
static struct attribute *mc13783_attr_16chans[] = {
&sensor_dev_attr_in8_input.dev_attr.attr,
&sensor_dev_attr_in9_input.dev_attr.attr,
&sensor_dev_attr_in10_input.dev_attr.attr,
@ -127,8 +147,8 @@ static struct attribute *mc13783_attr[] = {
NULL
};
static const struct attribute_group mc13783_group = {
.attrs = mc13783_attr,
static const struct attribute_group mc13783_group_16chans = {
.attrs = mc13783_attr_16chans,
};
/* last four channels may be occupied by the touchscreen */
@ -156,24 +176,37 @@ static int __init mc13783_adc_probe(struct platform_device *pdev)
{
struct mc13783_adc_priv *priv;
int ret;
const struct platform_device_id *id = platform_get_device_id(pdev);
char *dash;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->mc13xxx = dev_get_drvdata(pdev->dev.parent);
snprintf(priv->name, ARRAY_SIZE(priv->name), "%s", id->name);
dash = strchr(priv->name, '-');
if (dash)
*dash = '\0';
platform_set_drvdata(pdev, priv);
/* Register sysfs hooks */
ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group);
ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_base);
if (ret)
goto out_err_create1;
goto out_err_create_base;
if (id->driver_data & MC13783_ADC_16CHANS) {
ret = sysfs_create_group(&pdev->dev.kobj,
&mc13783_group_16chans);
if (ret)
goto out_err_create_16chans;
}
if (!mc13783_adc_use_touchscreen(pdev)) {
ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
if (ret)
goto out_err_create2;
goto out_err_create_ts;
}
priv->hwmon_dev = hwmon_device_register(&pdev->dev);
@ -184,17 +217,20 @@ static int __init mc13783_adc_probe(struct platform_device *pdev)
goto out_err_register;
}
return 0;
out_err_register:
if (!mc13783_adc_use_touchscreen(pdev))
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
out_err_create2:
out_err_create_ts:
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
out_err_create1:
if (id->driver_data & MC13783_ADC_16CHANS)
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
out_err_create_16chans:
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
out_err_create_base:
platform_set_drvdata(pdev, NULL);
kfree(priv);
@ -205,13 +241,17 @@ out_err_create1:
static int __devexit mc13783_adc_remove(struct platform_device *pdev)
{
struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data;
hwmon_device_unregister(priv->hwmon_dev);
if (!mc13783_adc_use_touchscreen(pdev))
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);
if (driver_data & MC13783_ADC_16CHANS)
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_16chans);
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_base);
platform_set_drvdata(pdev, NULL);
kfree(priv);
@ -219,12 +259,26 @@ static int __devexit mc13783_adc_remove(struct platform_device *pdev)
return 0;
}
static const struct platform_device_id mc13783_adc_idtable[] = {
{
.name = "mc13783-adc",
.driver_data = MC13783_ADC_16CHANS,
}, {
.name = "mc13892-adc",
.driver_data = MC13783_ADC_BPDIV2,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable);
static struct platform_driver mc13783_adc_driver = {
.remove = __devexit_p(mc13783_adc_remove),
.remove = __devexit_p(mc13783_adc_remove),
.driver = {
.owner = THIS_MODULE,
.name = MC13783_ADC_NAME,
.name = DRIVER_NAME,
},
.id_table = mc13783_adc_idtable,
};
static int __init mc13783_adc_init(void)
@ -243,4 +297,3 @@ module_exit(mc13783_adc_exit);
MODULE_DESCRIPTION("MC13783 ADC driver");
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" MC13783_ADC_NAME);

171
drivers/hwmon/mcp3021.c Normal file
View File

@ -0,0 +1,171 @@
/*
* mcp3021.c - driver for the Microchip MCP3021 chip
*
* Copyright (C) 2008-2009, 2012 Freescale Semiconductor, Inc.
* Author: Mingkai Hu <Mingkai.hu@freescale.com>
*
* This driver export the value of analog input voltage to sysfs, the
* voltage unit is mV. Through the sysfs interface, lm-sensors tool
* can also display the input voltage.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/hwmon.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/device.h>
/* Vdd info */
#define MCP3021_VDD_MAX 5500
#define MCP3021_VDD_MIN 2700
#define MCP3021_VDD_REF 3300
/* output format */
#define MCP3021_SAR_SHIFT 2
#define MCP3021_SAR_MASK 0x3ff
#define MCP3021_OUTPUT_RES 10 /* 10-bit resolution */
#define MCP3021_OUTPUT_SCALE 4
/*
* Client data (each client gets its own)
*/
struct mcp3021_data {
struct device *hwmon_dev;
u32 vdd; /* device power supply */
};
static int mcp3021_read16(struct i2c_client *client)
{
int ret;
u16 reg;
__be16 buf;
ret = i2c_master_recv(client, (char *)&buf, 2);
if (ret < 0)
return ret;
if (ret != 2)
return -EIO;
/* The output code of the MCP3021 is transmitted with MSB first. */
reg = be16_to_cpu(buf);
/*
* The ten-bit output code is composed of the lower 4-bit of the
* first byte and the upper 6-bit of the second byte.
*/
reg = (reg >> MCP3021_SAR_SHIFT) & MCP3021_SAR_MASK;
return reg;
}
static inline u16 volts_from_reg(u16 vdd, u16 val)
{
if (val == 0)
return 0;
val = val * MCP3021_OUTPUT_SCALE - MCP3021_OUTPUT_SCALE / 2;
return val * DIV_ROUND_CLOSEST(vdd,
(1 << MCP3021_OUTPUT_RES) * MCP3021_OUTPUT_SCALE);
}
static ssize_t show_in_input(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct mcp3021_data *data = i2c_get_clientdata(client);
int reg, in_input;
reg = mcp3021_read16(client);
if (reg < 0)
return reg;
in_input = volts_from_reg(data->vdd, reg);
return sprintf(buf, "%d\n", in_input);
}
static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL);
static int mcp3021_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err;
struct mcp3021_data *data = NULL;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
data = kzalloc(sizeof(struct mcp3021_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
i2c_set_clientdata(client, data);
if (client->dev.platform_data) {
data->vdd = *(u32 *)client->dev.platform_data;
if (data->vdd > MCP3021_VDD_MAX ||
data->vdd < MCP3021_VDD_MIN) {
err = -EINVAL;
goto exit_free;
}
} else
data->vdd = MCP3021_VDD_REF;
err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
if (err)
goto exit_free;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
return 0;
exit_remove:
sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
exit_free:
kfree(data);
return err;
}
static int mcp3021_remove(struct i2c_client *client)
{
struct mcp3021_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
kfree(data);
return 0;
}
static const struct i2c_device_id mcp3021_id[] = {
{ "mcp3021", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcp3021_id);
static struct i2c_driver mcp3021_driver = {
.driver = {
.name = "mcp3021",
},
.probe = mcp3021_probe,
.remove = mcp3021_remove,
.id_table = mcp3021_id,
};
module_i2c_driver(mcp3021_driver);
MODULE_AUTHOR("Mingkai Hu <Mingkai.hu@freescale.com>");
MODULE_DESCRIPTION("Microchip MCP3021 driver");
MODULE_LICENSE("GPL");

View File

@ -72,8 +72,10 @@ MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
#define TEMP_CRIT_HYST 2
#define TEMP_WARN 3
#define TEMP_WARN_HYST 4
/* only crit and crit_hyst affect real-time alarm status
* current crit crit_hyst warn warn_hyst */
/*
* only crit and crit_hyst affect real-time alarm status
* current crit crit_hyst warn warn_hyst
*/
static const u16 W83795_REG_TEMP[][5] = {
{0x21, 0x96, 0x97, 0x98, 0x99}, /* TD1/TR1 */
{0x22, 0x9a, 0x9b, 0x9c, 0x9d}, /* TD2/TR2 */
@ -354,26 +356,34 @@ struct w83795_data {
u8 temp_mode; /* Bit vector, 0 = TR, 1 = TD */
u8 temp_src[3]; /* Register value */
u8 enable_dts; /* Enable PECI and SB-TSI,
u8 enable_dts; /*
* Enable PECI and SB-TSI,
* bit 0: =1 enable, =0 disable,
* bit 1: =1 AMD SB-TSI, =0 Intel PECI */
* bit 1: =1 AMD SB-TSI, =0 Intel PECI
*/
u8 has_dts; /* Enable monitor DTS temp */
s8 dts[8]; /* Register value */
u8 dts_read_vrlsb[8]; /* Register value */
s8 dts_ext[4]; /* Register value */
u8 has_pwm; /* 795g supports 8 pwm, 795adg only supports 2,
u8 has_pwm; /*
* 795g supports 8 pwm, 795adg only supports 2,
* no config register, only affected by chip
* type */
u8 pwm[8][5]; /* Register value, output, freq, start,
* non stop, stop time */
* type
*/
u8 pwm[8][5]; /*
* Register value, output, freq, start,
* non stop, stop time
*/
u16 clkin; /* CLKIN frequency in kHz */
u8 pwm_fcms[2]; /* Register value */
u8 pwm_tfmr[6]; /* Register value */
u8 pwm_fomc; /* Register value */
u16 target_speed[8]; /* Register value, target speed for speed
* cruise */
u16 target_speed[8]; /*
* Register value, target speed for speed
* cruise
*/
u8 tol_speed; /* tolerance of target speed */
u8 pwm_temp[6][4]; /* TTTI, CTFS, HCT, HOT */
u8 sf4_reg[6][2][7]; /* 6 temp, temp/dcpwm, 7 registers */
@ -482,8 +492,10 @@ static void w83795_update_limits(struct i2c_client *client)
/* Read the fan limits */
lsb = 0; /* Silent false gcc warning */
for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
/* Each register contains LSB for 2 fans, but we want to
* read it only once to save time */
/*
* Each register contains LSB for 2 fans, but we want to
* read it only once to save time
*/
if ((i & 1) == 0 && (data->has_fan & (3 << i)))
lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i));
@ -665,9 +677,11 @@ static struct w83795_data *w83795_update_device(struct device *dev)
w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT));
}
/* Update intrusion and alarms
/*
* Update intrusion and alarms
* It is important to read intrusion first, because reading from
* register SMI STS6 clears the interrupt status temporarily. */
* register SMI STS6 clears the interrupt status temporarily.
*/
tmp = w83795_read(client, W83795_REG_ALARM_CTRL);
/* Switch to interrupt status for intrusion if needed */
if (tmp & ALARM_CTRL_RTSACS)
@ -929,6 +943,14 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
if (val < 1 || val > 2)
return -EINVAL;
#ifndef CONFIG_SENSORS_W83795_FANCTRL
if (val > 1) {
dev_warn(dev, "Automatic fan speed control support disabled\n");
dev_warn(dev, "Build with CONFIG_SENSORS_W83795_FANCTRL=y if you want it\n");
return -EOPNOTSUPP;
}
#endif
mutex_lock(&data->update_lock);
switch (val) {
case 1:
@ -1595,8 +1617,10 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
#define NOT_USED -1
/* Don't change the attribute order, _max, _min and _beep are accessed by index
* somewhere else in the code */
/*
* Don't change the attribute order, _max, _min and _beep are accessed by index
* somewhere else in the code
*/
#define SENSOR_ATTR_IN(index) { \
SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \
IN_READ, index), \
@ -1610,8 +1634,10 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
show_alarm_beep, store_beep, BEEP_ENABLE, \
index + ((index > 14) ? 1 : 0)) }
/* Don't change the attribute order, _beep is accessed by index
* somewhere else in the code */
/*
* Don't change the attribute order, _beep is accessed by index
* somewhere else in the code
*/
#define SENSOR_ATTR_FAN(index) { \
SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \
NULL, FAN_INPUT, index - 1), \
@ -1625,23 +1651,25 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
#define SENSOR_ATTR_PWM(index) { \
SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \
store_pwm, PWM_OUTPUT, index - 1), \
SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \
show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO, \
show_pwm_mode, NULL, NOT_USED, index - 1), \
SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \
show_pwm, store_pwm, PWM_FREQ, index - 1), \
SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \
show_pwm, store_pwm, PWM_NONSTOP, index - 1), \
SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \
show_pwm, store_pwm, PWM_START, index - 1), \
SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \
show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \
SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \
show_pwm, store_pwm, PWM_FREQ, index - 1), \
SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \
show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO, \
show_pwm_mode, NULL, NOT_USED, index - 1), \
SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \
show_fanin, store_fanin, FANIN_TARGET, index - 1) }
/* Don't change the attribute order, _beep is accessed by index
* somewhere else in the code */
/*
* Don't change the attribute order, _beep is accessed by index
* somewhere else in the code
*/
#define SENSOR_ATTR_DTS(index) { \
SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \
show_dts_mode, NULL, NOT_USED, index - 7), \
@ -1660,8 +1688,10 @@ store_sf_setup(struct device *dev, struct device_attribute *attr,
SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \
show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) }
/* Don't change the attribute order, _beep is accessed by index
* somewhere else in the code */
/*
* Don't change the attribute order, _beep is accessed by index
* somewhere else in the code
*/
#define SENSOR_ATTR_TEMP(index) { \
SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 4 ? S_IWUSR : 0), \
show_temp_mode, store_temp_mode, NOT_USED, index - 1), \
@ -1867,8 +1897,10 @@ static int w83795_get_device_id(struct i2c_client *client)
device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID);
/* Special case for rev. A chips; can't be checked first because later
revisions emulate this for compatibility */
/*
* Special case for rev. A chips; can't be checked first because later
* revisions emulate this for compatibility
*/
if (device_id < 0 || (device_id & 0xf0) != 0x50) {
int alt_id;
@ -1920,8 +1952,10 @@ static int w83795_detect(struct i2c_client *client,
return -ENODEV;
}
/* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR
should match */
/*
* If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR
* should match
*/
if ((bank & 0x07) == 0) {
i2c_addr = i2c_smbus_read_byte_data(client,
W83795_REG_I2C_ADDR);
@ -1933,10 +1967,12 @@ static int w83795_detect(struct i2c_client *client,
}
}
/* Check 795 chip type: 795G or 795ADG
Usually we don't write to chips during detection, but here we don't
quite have the choice; hopefully it's OK, we are about to return
success anyway */
/*
* Check 795 chip type: 795G or 795ADG
* Usually we don't write to chips during detection, but here we don't
* quite have the choice; hopefully it's OK, we are about to return
* success anyway
*/
if ((bank & 0x07) != 0)
i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL,
bank & ~0x07);
@ -1953,6 +1989,14 @@ static int w83795_detect(struct i2c_client *client,
return 0;
}
#ifdef CONFIG_SENSORS_W83795_FANCTRL
#define NUM_PWM_ATTRIBUTES ARRAY_SIZE(w83795_pwm[0])
#define NUM_TEMP_ATTRIBUTES ARRAY_SIZE(w83795_temp[0])
#else
#define NUM_PWM_ATTRIBUTES 4
#define NUM_TEMP_ATTRIBUTES 8
#endif
static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
const struct device_attribute *))
{
@ -2006,24 +2050,18 @@ static int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
}
}
#ifdef CONFIG_SENSORS_W83795_FANCTRL
for (i = 0; i < data->has_pwm; i++) {
for (j = 0; j < ARRAY_SIZE(w83795_pwm[0]); j++) {
for (j = 0; j < NUM_PWM_ATTRIBUTES; j++) {
err = fn(dev, &w83795_pwm[i][j].dev_attr);
if (err)
return err;
}
}
#endif
for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) {
if (!(data->has_temp & (1 << i)))
continue;
#ifdef CONFIG_SENSORS_W83795_FANCTRL
for (j = 0; j < ARRAY_SIZE(w83795_temp[0]); j++) {
#else
for (j = 0; j < 8; j++) {
#endif
for (j = 0; j < NUM_TEMP_ATTRIBUTES; j++) {
if (j == 7 && !data->enable_beep)
continue;
err = fn(dev, &w83795_temp[i][j].dev_attr);
@ -2183,8 +2221,10 @@ static int w83795_probe(struct i2c_client *client,
/* The W83795G has a dedicated BEEP pin */
data->enable_beep = 1;
} else {
/* The W83795ADG has a shared pin for OVT# and BEEP, so you
* can't have both */
/*
* The W83795ADG has a shared pin for OVT# and BEEP, so you
* can't have both
*/
tmp = w83795_read(client, W83795_REG_OVT_CFG);
if ((tmp & OVT_CFG_SEL) == 0)
data->enable_beep = 1;