Commit 71219b34 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-linus-v4.17' of...

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

Pull hwmon updates from Guenter Roeck:

 - added chip support: new Centaur CPUs, ADM1272, NCT6796D

 - ucd9000: added debugfs attributes, gpio support

 - cleanup and minor bug fixes

* tag 'hwmon-for-linus-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (via-cputemp) support new centaur CPUs
  hwmon: (nct6775) Fix writing pwmX_mode
  hwmon: (lm92) Add max6635 to lm92_id[]
  hwmon: (pmbus/adm1275) Add support for ADM1272
  hwmon: (lm92) Do not try to detect MAX6635
  hwmon: (ucd9000) Add debugfs attributes to provide mfr_status
  hwmon: (ucd9000) Add gpio chip interface
  hwmon: (nct6775) Add support for NCT6796D
  hwmon: (nct6775) Initialize boolean variables with declaration
  hwmon: (nct6775) Improve fan6/pwm6 support
  hwmon: (nct6775) Use NUM_FAN consistently
  hwmon: (g762) handle cleanup with devm_add_action
  hwmon: (sht3x) Update data sheet URL
  hwmon: (sht21) Update data sheet URLs
  hwmon: (pmbus/adm1275) Accept negative page register values
  hwmon: (pmbus/max8688) Accept negative page register values
parents c18bb396 e3a2d2be
...@@ -6,6 +6,10 @@ Supported chips: ...@@ -6,6 +6,10 @@ Supported chips:
Prefix: 'adm1075' Prefix: 'adm1075'
Addresses scanned: - Addresses scanned: -
Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1075.pdf Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1075.pdf
* Analog Devices ADM1272
Prefix: 'adm1272'
Addresses scanned: -
Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1272.pdf
* Analog Devices ADM1275 * Analog Devices ADM1275
Prefix: 'adm1275' Prefix: 'adm1275'
Addresses scanned: - Addresses scanned: -
...@@ -29,11 +33,11 @@ Author: Guenter Roeck <linux@roeck-us.net> ...@@ -29,11 +33,11 @@ Author: Guenter Roeck <linux@roeck-us.net>
Description Description
----------- -----------
This driver supports hardware monitoring for Analog Devices ADM1075, ADM1275, This driver supports hardware monitoring for Analog Devices ADM1075, ADM1272,
ADM1276, ADM1278, ADM1293, and ADM1294 Hot-Swap Controller and Digital ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294 Hot-Swap Controller and
Power Monitors. Digital Power Monitors.
ADM1075, ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294 are hot-swap ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294 are hot-swap
controllers that allow a circuit board to be removed from or inserted into controllers that allow a circuit board to be removed from or inserted into
a live backplane. They also feature current and voltage readback via an a live backplane. They also feature current and voltage readback via an
integrated 12 bit analog-to-digital converter (ADC), accessed using a integrated 12 bit analog-to-digital converter (ADC), accessed using a
...@@ -100,11 +104,10 @@ power1_input_lowest Lowest observed input power. ADM1293 and ADM1294 only. ...@@ -100,11 +104,10 @@ power1_input_lowest Lowest observed input power. ADM1293 and ADM1294 only.
power1_input_highest Highest observed input power. power1_input_highest Highest observed input power.
power1_reset_history Write any value to reset history. power1_reset_history Write any value to reset history.
Power attributes are supported on ADM1075, ADM1276, Power attributes are supported on ADM1075, ADM1272,
ADM1293, and ADM1294. ADM1276, ADM1293, and ADM1294.
temp1_input Chip temperature. temp1_input Chip temperature.
Temperature attributes are only available on ADM1278.
temp1_max Maximum chip temperature. temp1_max Maximum chip temperature.
temp1_max_alarm Temperature alarm. temp1_max_alarm Temperature alarm.
temp1_crit Critical chip temperature. temp1_crit Critical chip temperature.
...@@ -112,4 +115,5 @@ temp1_crit_alarm Critical temperature high alarm. ...@@ -112,4 +115,5 @@ temp1_crit_alarm Critical temperature high alarm.
temp1_highest Highest observed temperature. temp1_highest Highest observed temperature.
temp1_reset_history Write any value to reset history. temp1_reset_history Write any value to reset history.
Temperature attributes are supported on ADM1278. Temperature attributes are supported on ADM1272 and
ADM1278.
...@@ -11,10 +11,8 @@ Supported chips: ...@@ -11,10 +11,8 @@ Supported chips:
Addresses scanned: none, force parameter needed Addresses scanned: none, force parameter needed
Datasheet: http://www.national.com/pf/LM/LM76.html Datasheet: http://www.national.com/pf/LM/LM76.html
* Maxim MAX6633/MAX6634/MAX6635 * Maxim MAX6633/MAX6634/MAX6635
Prefix: 'lm92' Prefix: 'max6635'
Addresses scanned: I2C 0x48 - 0x4b Addresses scanned: none, force parameter needed
MAX6633 with address in 0x40 - 0x47, 0x4c - 0x4f needs force parameter
and MAX6634 with address in 0x4c - 0x4f needs force parameter
Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074 Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074
Authors: Authors:
......
...@@ -36,6 +36,14 @@ Supported chips: ...@@ -36,6 +36,14 @@ Supported chips:
Prefix: 'nct6793' Prefix: 'nct6793'
Addresses scanned: ISA address retrieved from Super I/O registers Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request Datasheet: Available from Nuvoton upon request
* Nuvoton NCT6795D
Prefix: 'nct6795'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
* Nuvoton NCT6796D
Prefix: 'nct6796'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
Authors: Authors:
Guenter Roeck <linux@roeck-us.net> Guenter Roeck <linux@roeck-us.net>
...@@ -88,10 +96,10 @@ The mode works for fan1-fan5. ...@@ -88,10 +96,10 @@ The mode works for fan1-fan5.
sysfs attributes sysfs attributes
---------------- ----------------
pwm[1-5] - this file stores PWM duty cycle or DC value (fan speed) in range: pwm[1-7] - this file stores PWM duty cycle or DC value (fan speed) in range:
0 (lowest speed) to 255 (full) 0 (lowest speed) to 255 (full)
pwm[1-5]_enable - this file controls mode of fan/temperature control: pwm[1-7]_enable - this file controls mode of fan/temperature control:
* 0 Fan control disabled (fans set to maximum speed) * 0 Fan control disabled (fans set to maximum speed)
* 1 Manual mode, write to pwm[0-5] any value 0-255 * 1 Manual mode, write to pwm[0-5] any value 0-255
* 2 "Thermal Cruise" mode * 2 "Thermal Cruise" mode
...@@ -99,16 +107,16 @@ pwm[1-5]_enable - this file controls mode of fan/temperature control: ...@@ -99,16 +107,16 @@ pwm[1-5]_enable - this file controls mode of fan/temperature control:
* 4 "Smart Fan III" mode (NCT6775F only) * 4 "Smart Fan III" mode (NCT6775F only)
* 5 "Smart Fan IV" mode * 5 "Smart Fan IV" mode
pwm[1-5]_mode - controls if output is PWM or DC level pwm[1-7]_mode - controls if output is PWM or DC level
* 0 DC output * 0 DC output
* 1 PWM output * 1 PWM output
Common fan control attributes Common fan control attributes
----------------------------- -----------------------------
pwm[1-5]_temp_sel Temperature source. Value is temperature sensor index. pwm[1-7]_temp_sel Temperature source. Value is temperature sensor index.
For example, select '1' for temp1_input. For example, select '1' for temp1_input.
pwm[1-5]_weight_temp_sel pwm[1-7]_weight_temp_sel
Secondary temperature source. Value is temperature Secondary temperature source. Value is temperature
sensor index. For example, select '1' for temp1_input. sensor index. For example, select '1' for temp1_input.
Set to 0 to disable secondary temperature control. Set to 0 to disable secondary temperature control.
...@@ -116,16 +124,16 @@ pwm[1-5]_weight_temp_sel ...@@ -116,16 +124,16 @@ pwm[1-5]_weight_temp_sel
If secondary temperature functionality is enabled, it is controlled with the If secondary temperature functionality is enabled, it is controlled with the
following attributes. following attributes.
pwm[1-5]_weight_duty_step pwm[1-7]_weight_duty_step
Duty step size. Duty step size.
pwm[1-5]_weight_temp_step pwm[1-7]_weight_temp_step
Temperature step size. With each step over Temperature step size. With each step over
temp_step_base, the value of weight_duty_step is added temp_step_base, the value of weight_duty_step is added
to the current pwm value. to the current pwm value.
pwm[1-5]_weight_temp_step_base pwm[1-7]_weight_temp_step_base
Temperature at which secondary temperature control kicks Temperature at which secondary temperature control kicks
in. in.
pwm[1-5]_weight_temp_step_tol pwm[1-7]_weight_temp_step_tol
Temperature step tolerance. Temperature step tolerance.
Thermal Cruise mode (2) Thermal Cruise mode (2)
...@@ -133,9 +141,9 @@ Thermal Cruise mode (2) ...@@ -133,9 +141,9 @@ Thermal Cruise mode (2)
If the temperature is in the range defined by: If the temperature is in the range defined by:
pwm[1-5]_target_temp Target temperature, unit millidegree Celsius pwm[1-7]_target_temp Target temperature, unit millidegree Celsius
(range 0 - 127000) (range 0 - 127000)
pwm[1-5]_temp_tolerance pwm[1-7]_temp_tolerance
Target temperature tolerance, unit millidegree Celsius Target temperature tolerance, unit millidegree Celsius
there are no changes to fan speed. Once the temperature leaves the interval, fan there are no changes to fan speed. Once the temperature leaves the interval, fan
...@@ -143,14 +151,14 @@ speed increases (if temperature is higher that desired) or decreases (if ...@@ -143,14 +151,14 @@ speed increases (if temperature is higher that desired) or decreases (if
temperature is lower than desired), using the following limits and time temperature is lower than desired), using the following limits and time
intervals. intervals.
pwm[1-5]_start fan pwm start value (range 1 - 255), to start fan pwm[1-7]_start fan pwm start value (range 1 - 255), to start fan
when the temperature is above defined range. when the temperature is above defined range.
pwm[1-5]_floor lowest fan pwm (range 0 - 255) if temperature is below pwm[1-7]_floor lowest fan pwm (range 0 - 255) if temperature is below
the defined range. If set to 0, the fan is expected to the defined range. If set to 0, the fan is expected to
stop if the temperature is below the defined range. stop if the temperature is below the defined range.
pwm[1-5]_step_up_time milliseconds before fan speed is increased pwm[1-7]_step_up_time milliseconds before fan speed is increased
pwm[1-5]_step_down_time milliseconds before fan speed is decreased pwm[1-7]_step_down_time milliseconds before fan speed is decreased
pwm[1-5]_stop_time how many milliseconds must elapse to switch pwm[1-7]_stop_time how many milliseconds must elapse to switch
corresponding fan off (when the temperature was below corresponding fan off (when the temperature was below
defined range). defined range).
...@@ -159,8 +167,8 @@ Speed Cruise mode (3) ...@@ -159,8 +167,8 @@ Speed Cruise mode (3)
This modes tries to keep the fan speed constant. This modes tries to keep the fan speed constant.
fan[1-5]_target Target fan speed fan[1-7]_target Target fan speed
fan[1-5]_tolerance fan[1-7]_tolerance
Target speed tolerance Target speed tolerance
...@@ -177,19 +185,19 @@ points should be set to higher temperatures and higher pwm values to achieve ...@@ -177,19 +185,19 @@ points should be set to higher temperatures and higher pwm values to achieve
higher fan speeds with increasing temperature. The last data point reflects higher fan speeds with increasing temperature. The last data point reflects
critical temperature mode, in which the fans should run at full speed. critical temperature mode, in which the fans should run at full speed.
pwm[1-5]_auto_point[1-7]_pwm pwm[1-7]_auto_point[1-7]_pwm
pwm value to be set if temperature reaches matching pwm value to be set if temperature reaches matching
temperature range. temperature range.
pwm[1-5]_auto_point[1-7]_temp pwm[1-7]_auto_point[1-7]_temp
Temperature over which the matching pwm is enabled. Temperature over which the matching pwm is enabled.
pwm[1-5]_temp_tolerance pwm[1-7]_temp_tolerance
Temperature tolerance, unit millidegree Celsius Temperature tolerance, unit millidegree Celsius
pwm[1-5]_crit_temp_tolerance pwm[1-7]_crit_temp_tolerance
Temperature tolerance for critical temperature, Temperature tolerance for critical temperature,
unit millidegree Celsius unit millidegree Celsius
pwm[1-5]_step_up_time milliseconds before fan speed is increased pwm[1-7]_step_up_time milliseconds before fan speed is increased
pwm[1-5]_step_down_time milliseconds before fan speed is decreased pwm[1-7]_step_down_time milliseconds before fan speed is decreased
Usage Notes Usage Notes
----------- -----------
......
...@@ -6,13 +6,13 @@ Supported chips: ...@@ -6,13 +6,13 @@ Supported chips:
Prefix: 'sht21' Prefix: 'sht21'
Addresses scanned: none Addresses scanned: none
Datasheet: Publicly available at the Sensirion website Datasheet: Publicly available at the Sensirion website
http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf http://www.sensirion.com/file/datasheet_sht21
* Sensirion SHT25 * Sensirion SHT25
Prefix: 'sht21' Prefix: 'sht25'
Addresses scanned: none Addresses scanned: none
Datasheet: Publicly available at the Sensirion website Datasheet: Publicly available at the Sensirion website
http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT25.pdf http://www.sensirion.com/file/datasheet_sht25
Author: Author:
Urs Fleisch <urs.fleisch@sensirion.com> Urs Fleisch <urs.fleisch@sensirion.com>
......
...@@ -5,7 +5,7 @@ Supported chips: ...@@ -5,7 +5,7 @@ Supported chips:
* Sensirion SHT3x-DIS * Sensirion SHT3x-DIS
Prefix: 'sht3x' Prefix: 'sht3x'
Addresses scanned: none Addresses scanned: none
Datasheet: http://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/Humidity/Sensirion_Humidity_Datasheet_SHT3x_DIS.pdf Datasheet: https://www.sensirion.com/file/datasheet_sht3x_digital
Author: Author:
David Frey <david.frey@sensirion.com> David Frey <david.frey@sensirion.com>
......
...@@ -1231,8 +1231,9 @@ config SENSORS_NCT6775 ...@@ -1231,8 +1231,9 @@ config SENSORS_NCT6775
help help
If you say yes here you get support for the hardware monitoring If you say yes here you get support for the hardware monitoring
functionality of the Nuvoton NCT6106D, NCT6775F, NCT6776F, NCT6779D, functionality of the Nuvoton NCT6106D, NCT6775F, NCT6776F, NCT6779D,
NCT6791D, NCT6792D, NCT6793D, and compatible Super-I/O chips. This NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D, and compatible
driver replaces the w83627ehf driver for NCT6775F and NCT6776F. Super-I/O chips. This driver replaces the w83627ehf driver for
NCT6775F and NCT6776F.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called nct6775. will be called nct6775.
......
...@@ -128,7 +128,6 @@ enum g762_regs { ...@@ -128,7 +128,6 @@ enum g762_regs {
G762_REG_FAN_CMD2_GEAR_MODE_1)) >> 2)) G762_REG_FAN_CMD2_GEAR_MODE_1)) >> 2))
struct g762_data { struct g762_data {
struct device *hwmon_dev;
struct i2c_client *client; struct i2c_client *client;
struct clk *clk; struct clk *clk;
...@@ -594,6 +593,14 @@ MODULE_DEVICE_TABLE(of, g762_dt_match); ...@@ -594,6 +593,14 @@ MODULE_DEVICE_TABLE(of, g762_dt_match);
* call to g762_of_clock_disable(). Note that a reference to clock is kept * call to g762_of_clock_disable(). Note that a reference to clock is kept
* in our private data structure to be used in this function. * in our private data structure to be used in this function.
*/ */
static void g762_of_clock_disable(void *data)
{
struct g762_data *g762 = data;
clk_disable_unprepare(g762->clk);
clk_put(g762->clk);
}
static int g762_of_clock_enable(struct i2c_client *client) static int g762_of_clock_enable(struct i2c_client *client)
{ {
struct g762_data *data; struct g762_data *data;
...@@ -626,6 +633,7 @@ static int g762_of_clock_enable(struct i2c_client *client) ...@@ -626,6 +633,7 @@ static int g762_of_clock_enable(struct i2c_client *client)
data = i2c_get_clientdata(client); data = i2c_get_clientdata(client);
data->clk = clk; data->clk = clk;
devm_add_action(&client->dev, g762_of_clock_disable, data);
return 0; return 0;
clk_unprep: clk_unprep:
...@@ -637,17 +645,6 @@ static int g762_of_clock_enable(struct i2c_client *client) ...@@ -637,17 +645,6 @@ static int g762_of_clock_enable(struct i2c_client *client)
return ret; return ret;
} }
static void g762_of_clock_disable(struct i2c_client *client)
{
struct g762_data *data = i2c_get_clientdata(client);
if (!data->clk)
return;
clk_disable_unprepare(data->clk);
clk_put(data->clk);
}
static int g762_of_prop_import_one(struct i2c_client *client, static int g762_of_prop_import_one(struct i2c_client *client,
const char *pname, const char *pname,
int (*psetter)(struct device *dev, int (*psetter)(struct device *dev,
...@@ -698,8 +695,6 @@ static int g762_of_clock_enable(struct i2c_client *client) ...@@ -698,8 +695,6 @@ static int g762_of_clock_enable(struct i2c_client *client)
{ {
return 0; return 0;
} }
static void g762_of_clock_disable(struct i2c_client *client) { }
#endif #endif
/* /*
...@@ -1054,6 +1049,7 @@ static inline int g762_fan_init(struct device *dev) ...@@ -1054,6 +1049,7 @@ static inline int g762_fan_init(struct device *dev)
static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id) static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
{ {
struct device *dev = &client->dev; struct device *dev = &client->dev;
struct device *hwmon_dev;
struct g762_data *data; struct g762_data *data;
int ret; int ret;
...@@ -1080,35 +1076,15 @@ static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -1080,35 +1076,15 @@ static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
return ret; return ret;
ret = g762_of_prop_import(client); ret = g762_of_prop_import(client);
if (ret) if (ret)
goto clock_dis; return ret;
/* ... or platform_data */ /* ... or platform_data */
ret = g762_pdata_prop_import(client); ret = g762_pdata_prop_import(client);
if (ret) if (ret)
goto clock_dis; return ret;
data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
data, g762_groups); data, g762_groups);
if (IS_ERR(data->hwmon_dev)) { return PTR_ERR_OR_ZERO(hwmon_dev);
ret = PTR_ERR(data->hwmon_dev);
goto clock_dis;
}
return 0;
clock_dis:
g762_of_clock_disable(client);
return ret;
}
static int g762_remove(struct i2c_client *client)
{
struct g762_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
g762_of_clock_disable(client);
return 0;
} }
static struct i2c_driver g762_driver = { static struct i2c_driver g762_driver = {
...@@ -1117,7 +1093,6 @@ static struct i2c_driver g762_driver = { ...@@ -1117,7 +1093,6 @@ static struct i2c_driver g762_driver = {
.of_match_table = of_match_ptr(g762_dt_match), .of_match_table = of_match_ptr(g762_dt_match),
}, },
.probe = g762_probe, .probe = g762_probe,
.remove = g762_remove,
.id_table = g762_id, .id_table = g762_id,
}; };
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
*/ */
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
I2C_CLIENT_END }; I2C_CLIENT_END };
enum chips { lm92, max6635 };
/* The LM92 registers */ /* The LM92 registers */
#define LM92_REG_CONFIG 0x01 /* 8-bit, RW */ #define LM92_REG_CONFIG 0x01 /* 8-bit, RW */
...@@ -259,62 +260,6 @@ static void lm92_init_client(struct i2c_client *client) ...@@ -259,62 +260,6 @@ static void lm92_init_client(struct i2c_client *client)
config & 0xFE); config & 0xFE);
} }
/*
* The MAX6635 has no identification register, so we have to use tricks
* to identify it reliably. This is somewhat slow.
* Note that we do NOT rely on the 2 MSB of the configuration register
* always reading 0, as suggested by the datasheet, because it was once
* reported not to be true.
*/
static int max6635_check(struct i2c_client *client)
{
u16 temp_low, temp_high, temp_hyst, temp_crit;
u8 conf;
int i;
/*
* No manufacturer ID register, so a read from this address will
* always return the last read value.
*/
temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW);
if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low)
return 0;
temp_high = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HIGH);
if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_high)
return 0;
/* Limits are stored as integer values (signed, 9-bit). */
if ((temp_low & 0x7f00) || (temp_high & 0x7f00))
return 0;
temp_hyst = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HYST);
temp_crit = i2c_smbus_read_word_data(client, LM92_REG_TEMP_CRIT);
if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00))
return 0;
/*
* Registers addresses were found to cycle over 16-byte boundaries.
* We don't test all registers with all offsets so as to save some
* reads and time, but this should still be sufficient to dismiss
* non-MAX6635 chips.
*/
conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG);
for (i = 16; i < 96; i *= 2) {
if (temp_hyst != i2c_smbus_read_word_data(client,
LM92_REG_TEMP_HYST + i - 16)
|| temp_crit != i2c_smbus_read_word_data(client,
LM92_REG_TEMP_CRIT + i)
|| temp_low != i2c_smbus_read_word_data(client,
LM92_REG_TEMP_LOW + i + 16)
|| temp_high != i2c_smbus_read_word_data(client,
LM92_REG_TEMP_HIGH + i + 32)
|| conf != i2c_smbus_read_byte_data(client,
LM92_REG_CONFIG + i))
return 0;
}
return 1;
}
static struct attribute *lm92_attrs[] = { static struct attribute *lm92_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr,
...@@ -348,8 +293,6 @@ static int lm92_detect(struct i2c_client *new_client, ...@@ -348,8 +293,6 @@ static int lm92_detect(struct i2c_client *new_client,
if ((config & 0xe0) == 0x00 && man_id == 0x0180) if ((config & 0xe0) == 0x00 && man_id == 0x0180)
pr_info("lm92: Found National Semiconductor LM92 chip\n"); pr_info("lm92: Found National Semiconductor LM92 chip\n");
else if (max6635_check(new_client))
pr_info("lm92: Found Maxim MAX6635 chip\n");
else else
return -ENODEV; return -ENODEV;
...@@ -387,8 +330,8 @@ static int lm92_probe(struct i2c_client *new_client, ...@@ -387,8 +330,8 @@ static int lm92_probe(struct i2c_client *new_client,
*/ */
static const struct i2c_device_id lm92_id[] = { static const struct i2c_device_id lm92_id[] = {
{ "lm92", 0 }, { "lm92", lm92 },
/* max6635 could be added here */ { "max6635", max6635 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, lm92_id); MODULE_DEVICE_TABLE(i2c, lm92_id);
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
* nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
* nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
* nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3 * nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3
* * nct6796d 14 7 7 2+6 0xd420 0xc1 0x5ca3
* *
* #temp lists the number of monitored temperature sources (first value) plus * #temp lists the number of monitored temperature sources (first value) plus
* the number of directly connectable temperature sensors (second value). * the number of directly connectable temperature sensors (second value).
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
#define USE_ALTERNATE #define USE_ALTERNATE
enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793, enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
nct6795 }; nct6795, nct6796 };
/* used to set data->name = nct6775_device_names[data->sio_kind] */ /* used to set data->name = nct6775_device_names[data->sio_kind] */
static const char * const nct6775_device_names[] = { static const char * const nct6775_device_names[] = {
...@@ -80,6 +80,7 @@ static const char * const nct6775_device_names[] = { ...@@ -80,6 +80,7 @@ static const char * const nct6775_device_names[] = {
"nct6792", "nct6792",
"nct6793", "nct6793",
"nct6795", "nct6795",
"nct6796",
}; };
static const char * const nct6775_sio_names[] __initconst = { static const char * const nct6775_sio_names[] __initconst = {
...@@ -91,6 +92,7 @@ static const char * const nct6775_sio_names[] __initconst = { ...@@ -91,6 +92,7 @@ static const char * const nct6775_sio_names[] __initconst = {
"NCT6792D", "NCT6792D",
"NCT6793D", "NCT6793D",
"NCT6795D", "NCT6795D",
"NCT6796D",
}; };
static unsigned short force_id; static unsigned short force_id;
...@@ -125,6 +127,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); ...@@ -125,6 +127,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
#define SIO_NCT6792_ID 0xc910 #define SIO_NCT6792_ID 0xc910
#define SIO_NCT6793_ID 0xd120 #define SIO_NCT6793_ID 0xd120
#define SIO_NCT6795_ID 0xd350 #define SIO_NCT6795_ID 0xd350
#define SIO_NCT6796_ID 0xd420
#define SIO_ID_MASK 0xFFF0 #define SIO_ID_MASK 0xFFF0
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
...@@ -201,7 +204,7 @@ superio_exit(int ioreg) ...@@ -201,7 +204,7 @@ superio_exit(int ioreg)
#define NUM_REG_ALARM 7 /* Max number of alarm registers */ #define NUM_REG_ALARM 7 /* Max number of alarm registers */
#define NUM_REG_BEEP 5 /* Max number of beep registers */ #define NUM_REG_BEEP 5 /* Max number of beep registers */
#define NUM_FAN 6 #define NUM_FAN 7
#define TEMP_SOURCE_VIRTUAL 0x1f #define TEMP_SOURCE_VIRTUAL 0x1f
...@@ -272,26 +275,26 @@ static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 }; ...@@ -272,26 +275,26 @@ static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
/* Advanced Fan control, some values are common for all fans */ /* Advanced Fan control, some values are common for all fans */
static const u16 NCT6775_REG_TARGET[] = { static const u16 NCT6775_REG_TARGET[] = {
0x101, 0x201, 0x301, 0x801, 0x901, 0xa01 }; 0x101, 0x201, 0x301, 0x801, 0x901, 0xa01, 0xb01 };
static const u16 NCT6775_REG_FAN_MODE[] = { static const u16 NCT6775_REG_FAN_MODE[] = {
0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 }; 0x102, 0x202, 0x302, 0x802, 0x902, 0xa02, 0xb02 };
static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = { static const u16 NCT6775_REG_FAN_STEP_DOWN_TIME[] = {
0x103, 0x203, 0x303, 0x803, 0x903, 0xa03 }; 0x103, 0x203, 0x303, 0x803, 0x903, 0xa03, 0xb03 };
static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = { static const u16 NCT6775_REG_FAN_STEP_UP_TIME[] = {
0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 }; 0x104, 0x204, 0x304, 0x804, 0x904, 0xa04, 0xb04 };
static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = {
0x105, 0x205, 0x305, 0x805, 0x905, 0xa05 }; 0x105, 0x205, 0x305, 0x805, 0x905, 0xa05, 0xb05 };
static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { static const u16 NCT6775_REG_FAN_START_OUTPUT[] = {
0x106, 0x206, 0x306, 0x806, 0x906, 0xa06 }; 0x106, 0x206, 0x306, 0x806, 0x906, 0xa06, 0xb06 };
static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a }; static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b }; static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
static const u16 NCT6775_REG_FAN_STOP_TIME[] = { static const u16 NCT6775_REG_FAN_STOP_TIME[] = {
0x107, 0x207, 0x307, 0x807, 0x907, 0xa07 }; 0x107, 0x207, 0x307, 0x807, 0x907, 0xa07, 0xb07 };
static const u16 NCT6775_REG_PWM[] = { static const u16 NCT6775_REG_PWM[] = {
0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 }; 0x109, 0x209, 0x309, 0x809, 0x909, 0xa09, 0xb09 };
static const u16 NCT6775_REG_PWM_READ[] = { static const u16 NCT6775_REG_PWM_READ[] = {
0x01, 0x03, 0x11, 0x13, 0x15, 0xa09 }; 0x01, 0x03, 0x11, 0x13, 0x15, 0xa09, 0xb09 };
static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 }; static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d }; static const u16 NCT6775_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d };
...@@ -314,7 +317,7 @@ static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = { ...@@ -314,7 +317,7 @@ static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
0x621, 0x622, 0x623, 0x624, 0x625, 0x626 }; 0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
static const u16 NCT6775_REG_TEMP_SEL[] = { static const u16 NCT6775_REG_TEMP_SEL[] = {
0x100, 0x200, 0x300, 0x800, 0x900, 0xa00 }; 0x100, 0x200, 0x300, 0x800, 0x900, 0xa00, 0xb00 };
static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = { static const u16 NCT6775_REG_WEIGHT_TEMP_SEL[] = {
0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 }; 0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
...@@ -330,9 +333,9 @@ static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = { ...@@ -330,9 +333,9 @@ static const u16 NCT6775_REG_WEIGHT_TEMP_BASE[] = {
static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 }; static const u16 NCT6775_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
static const u16 NCT6775_REG_AUTO_TEMP[] = { static const u16 NCT6775_REG_AUTO_TEMP[] = {
0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 }; 0x121, 0x221, 0x321, 0x821, 0x921, 0xa21, 0xb21 };
static const u16 NCT6775_REG_AUTO_PWM[] = { static const u16 NCT6775_REG_AUTO_PWM[] = {
0x127, 0x227, 0x327, 0x827, 0x927, 0xa27 }; 0x127, 0x227, 0x327, 0x827, 0x927, 0xa27, 0xb27 };
#define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p)) #define NCT6775_AUTO_TEMP(data, nr, p) ((data)->REG_AUTO_TEMP[nr] + (p))
#define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p)) #define NCT6775_AUTO_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
...@@ -340,9 +343,9 @@ static const u16 NCT6775_REG_AUTO_PWM[] = { ...@@ -340,9 +343,9 @@ static const u16 NCT6775_REG_AUTO_PWM[] = {
static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 }; static const u16 NCT6775_REG_CRITICAL_ENAB[] = { 0x134, 0x234, 0x334 };
static const u16 NCT6775_REG_CRITICAL_TEMP[] = { static const u16 NCT6775_REG_CRITICAL_TEMP[] = {
0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 }; 0x135, 0x235, 0x335, 0x835, 0x935, 0xa35, 0xb35 };
static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = { static const u16 NCT6775_REG_CRITICAL_TEMP_TOLERANCE[] = {
0x138, 0x238, 0x338, 0x838, 0x938, 0xa38 }; 0x138, 0x238, 0x338, 0x838, 0x938, 0xa38, 0xb38 };
static const char *const nct6775_temp_label[] = { static const char *const nct6775_temp_label[] = {
"", "",
...@@ -414,13 +417,15 @@ static const s8 NCT6776_BEEP_BITS[] = { ...@@ -414,13 +417,15 @@ static const s8 NCT6776_BEEP_BITS[] = {
30, 31 }; /* intrusion0, intrusion1 */ 30, 31 }; /* intrusion0, intrusion1 */
static const u16 NCT6776_REG_TOLERANCE_H[] = { static const u16 NCT6776_REG_TOLERANCE_H[] = {
0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c }; 0x10c, 0x20c, 0x30c, 0x80c, 0x90c, 0xa0c, 0xb0c };
static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 }; static const u8 NCT6776_REG_PWM_MODE[] = { 0x04, 0, 0, 0, 0, 0 };
static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 }; static const u8 NCT6776_PWM_MODE_MASK[] = { 0x01, 0, 0, 0, 0, 0 };
static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642 }; static const u16 NCT6776_REG_FAN_MIN[] = {
static const u16 NCT6776_REG_FAN_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 }; 0x63a, 0x63c, 0x63e, 0x640, 0x642, 0x64a, 0x64c };
static const u16 NCT6776_REG_FAN_PULSES[] = {
0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0 };
static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = { static const u16 NCT6776_REG_WEIGHT_DUTY_BASE[] = {
0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e }; 0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
...@@ -495,15 +500,15 @@ static const s8 NCT6779_BEEP_BITS[] = { ...@@ -495,15 +500,15 @@ static const s8 NCT6779_BEEP_BITS[] = {
30, 31 }; /* intrusion0, intrusion1 */ 30, 31 }; /* intrusion0, intrusion1 */
static const u16 NCT6779_REG_FAN[] = { static const u16 NCT6779_REG_FAN[] = {
0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba }; 0x4b0, 0x4b2, 0x4b4, 0x4b6, 0x4b8, 0x4ba, 0x660 };
static const u16 NCT6779_REG_FAN_PULSES[] = { static const u16 NCT6779_REG_FAN_PULSES[] = {
0x644, 0x645, 0x646, 0x647, 0x648, 0x649 }; 0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0 };
static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = { static const u16 NCT6779_REG_CRITICAL_PWM_ENABLE[] = {
0x136, 0x236, 0x336, 0x836, 0x936, 0xa36 }; 0x136, 0x236, 0x336, 0x836, 0x936, 0xa36, 0xb36 };
#define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01 #define NCT6779_CRITICAL_PWM_ENABLE_MASK 0x01
static const u16 NCT6779_REG_CRITICAL_PWM[] = { static const u16 NCT6779_REG_CRITICAL_PWM[] = {
0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 }; 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37, 0xb37 };
static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 }; static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 };
static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b }; static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
...@@ -570,12 +575,12 @@ static const u16 NCT6779_REG_TEMP_CRIT[32] = { ...@@ -570,12 +575,12 @@ static const u16 NCT6779_REG_TEMP_CRIT[32] = {
#define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28 #define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28
static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 }; static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[NUM_FAN] = { 0, 0x239 };
static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a }; static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[NUM_FAN] = { 0, 0x23a };
static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b }; static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[NUM_FAN] = { 0, 0x23b };
static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c }; static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[NUM_FAN] = { 0, 0x23c };
static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d }; static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[NUM_FAN] = { 0, 0x23d };
static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e }; static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e };
static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = { static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
0x459, 0x45A, 0x45B, 0x568, 0x45D }; 0x459, 0x45A, 0x45B, 0x568, 0x45D };
...@@ -707,6 +712,43 @@ static const char *const nct6795_temp_label[] = { ...@@ -707,6 +712,43 @@ static const char *const nct6795_temp_label[] = {
#define NCT6795_TEMP_MASK 0xbfffff7e #define NCT6795_TEMP_MASK 0xbfffff7e
static const char *const nct6796_temp_label[] = {
"",
"SYSTIN",
"CPUTIN",
"AUXTIN0",
"AUXTIN1",
"AUXTIN2",
"AUXTIN3",
"AUXTIN4",
"SMBUSMASTER 0",
"SMBUSMASTER 1",
"",
"",
"",
"",
"",
"",
"PECI Agent 0",
"PECI Agent 1",
"PCH_CHIP_CPU_MAX_TEMP",
"PCH_CHIP_TEMP",
"PCH_CPU_TEMP",
"PCH_MCH_TEMP",
"PCH_DIM0_TEMP",
"PCH_DIM1_TEMP",
"PCH_DIM2_TEMP",
"PCH_DIM3_TEMP",
"BYTE_TEMP0",
"BYTE_TEMP1",
"PECI Agent 0 Calibration",
"PECI Agent 1 Calibration",
"",
"Virtual_TEMP"
};
#define NCT6796_TEMP_MASK 0xbfff03fe
/* NCT6102D/NCT6106D specific data */ /* NCT6102D/NCT6106D specific data */
#define NCT6106_REG_VBAT 0x318 #define NCT6106_REG_VBAT 0x318
...@@ -1231,11 +1273,13 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) ...@@ -1231,11 +1273,13 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796:
return reg == 0x150 || reg == 0x153 || reg == 0x155 || return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) || ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
reg == 0x402 || reg == 0x402 ||
reg == 0x63a || reg == 0x63c || reg == 0x63e || reg == 0x63a || reg == 0x63c || reg == 0x63e ||
reg == 0x640 || reg == 0x642 || reg == 0x640 || reg == 0x642 || reg == 0x64a ||
reg == 0x64c || reg == 0x660 ||
reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 || reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
reg == 0x7b || reg == 0x7d; reg == 0x7b || reg == 0x7d;
} }
...@@ -1469,7 +1513,7 @@ static void nct6775_update_pwm(struct device *dev) ...@@ -1469,7 +1513,7 @@ static void nct6775_update_pwm(struct device *dev)
duty_is_dc = data->REG_PWM_MODE[i] && duty_is_dc = data->REG_PWM_MODE[i] &&
(nct6775_read_value(data, data->REG_PWM_MODE[i]) (nct6775_read_value(data, data->REG_PWM_MODE[i])
& data->PWM_MODE_MASK[i]); & data->PWM_MODE_MASK[i]);
data->pwm_mode[i] = duty_is_dc; data->pwm_mode[i] = !duty_is_dc;
fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]); fanmodecfg = nct6775_read_value(data, data->REG_FAN_MODE[i]);
for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) { for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
...@@ -1584,6 +1628,7 @@ static void nct6775_update_pwm_limits(struct device *dev) ...@@ -1584,6 +1628,7 @@ static void nct6775_update_pwm_limits(struct device *dev)
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796:
reg = nct6775_read_value(data, reg = nct6775_read_value(data,
data->REG_CRITICAL_PWM_ENABLE[i]); data->REG_CRITICAL_PWM_ENABLE[i]);
if (reg & data->CRITICAL_PWM_ENABLE_MASK) if (reg & data->CRITICAL_PWM_ENABLE_MASK)
...@@ -2092,6 +2137,8 @@ static umode_t nct6775_fan_is_visible(struct kobject *kobj, ...@@ -2092,6 +2137,8 @@ static umode_t nct6775_fan_is_visible(struct kobject *kobj,
return 0; return 0;
if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1) if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
return 0; return 0;
if (nr == 3 && !data->REG_FAN_PULSES[fan])
return 0;
if (nr == 4 && !(data->has_fan_min & BIT(fan))) if (nr == 4 && !(data->has_fan_min & BIT(fan)))
return 0; return 0;
if (nr == 5 && data->kind != nct6775) if (nr == 5 && data->kind != nct6775)
...@@ -2350,7 +2397,7 @@ show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf) ...@@ -2350,7 +2397,7 @@ show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
struct nct6775_data *data = nct6775_update_device(dev); struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
return sprintf(buf, "%d\n", !data->pwm_mode[sattr->index]); return sprintf(buf, "%d\n", data->pwm_mode[sattr->index]);
} }
static ssize_t static ssize_t
...@@ -2371,9 +2418,9 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, ...@@ -2371,9 +2418,9 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
if (val > 1) if (val > 1)
return -EINVAL; return -EINVAL;
/* Setting DC mode is not supported for all chips/channels */ /* Setting DC mode (0) is not supported for all chips/channels */
if (data->REG_PWM_MODE[nr] == 0) { if (data->REG_PWM_MODE[nr] == 0) {
if (val) if (!val)
return -EINVAL; return -EINVAL;
return count; return count;
} }
...@@ -2382,7 +2429,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, ...@@ -2382,7 +2429,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
data->pwm_mode[nr] = val; data->pwm_mode[nr] = val;
reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]); reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
reg &= ~data->PWM_MODE_MASK[nr]; reg &= ~data->PWM_MODE_MASK[nr];
if (val) if (!val)
reg |= data->PWM_MODE_MASK[nr]; reg |= data->PWM_MODE_MASK[nr];
nct6775_write_value(data, data->REG_PWM_MODE[nr], reg); nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
...@@ -3004,6 +3051,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, ...@@ -3004,6 +3051,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796:
nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
val); val);
reg = nct6775_read_value(data, reg = nct6775_read_value(data,
...@@ -3358,8 +3406,10 @@ static inline void nct6775_init_device(struct nct6775_data *data) ...@@ -3358,8 +3406,10 @@ static inline void nct6775_init_device(struct nct6775_data *data)
static void static void
nct6775_check_fan_inputs(struct nct6775_data *data) nct6775_check_fan_inputs(struct nct6775_data *data)
{ {
bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin; bool fan3pin = false, fan4pin = false, fan4min = false;
bool pwm3pin, pwm4pin, pwm5pin, pwm6pin; bool fan5pin = false, fan6pin = false, fan7pin = false;
bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
bool pwm6pin = false, pwm7pin = false;
int sioreg = data->sioreg; int sioreg = data->sioreg;
int regval; int regval;
...@@ -3376,12 +3426,6 @@ nct6775_check_fan_inputs(struct nct6775_data *data) ...@@ -3376,12 +3426,6 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
/* On NCT6775, fan4 shares pins with the fdc interface */ /* On NCT6775, fan4 shares pins with the fdc interface */
fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80); fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
fan4min = false;
fan5pin = false;
fan6pin = false;
pwm4pin = false;
pwm5pin = false;
pwm6pin = false;
} else if (data->kind == nct6776) { } else if (data->kind == nct6776) {
bool gpok = superio_inb(sioreg, 0x27) & 0x80; bool gpok = superio_inb(sioreg, 0x27) & 0x80;
const char *board_vendor, *board_name; const char *board_vendor, *board_name;
...@@ -3421,25 +3465,15 @@ nct6775_check_fan_inputs(struct nct6775_data *data) ...@@ -3421,25 +3465,15 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
fan5pin = superio_inb(sioreg, 0x1C) & 0x02; fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
fan4min = fan4pin; fan4min = fan4pin;
fan6pin = false;
pwm3pin = fan3pin; pwm3pin = fan3pin;
pwm4pin = false;
pwm5pin = false;
pwm6pin = false;
} else if (data->kind == nct6106) { } else if (data->kind == nct6106) {
regval = superio_inb(sioreg, 0x24); regval = superio_inb(sioreg, 0x24);
fan3pin = !(regval & 0x80); fan3pin = !(regval & 0x80);
pwm3pin = regval & 0x08; pwm3pin = regval & 0x08;
} else {
fan4pin = false; /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D */
fan4min = false; int regval_1b, regval_2a, regval_2f;
fan5pin = false; bool dsw_en;
fan6pin = false;
pwm4pin = false;
pwm5pin = false;
pwm6pin = false;
} else { /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, or NCT6795D */
int regval_1b, regval_2a, regval_eb;
regval = superio_inb(sioreg, 0x1c); regval = superio_inb(sioreg, 0x1c);
...@@ -3460,31 +3494,60 @@ nct6775_check_fan_inputs(struct nct6775_data *data) ...@@ -3460,31 +3494,60 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
break; break;
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796:
regval_1b = superio_inb(sioreg, 0x1b); regval_1b = superio_inb(sioreg, 0x1b);
regval_2a = superio_inb(sioreg, 0x2a); regval_2a = superio_inb(sioreg, 0x2a);
regval_2f = superio_inb(sioreg, 0x2f);
dsw_en = regval_2f & BIT(3);
if (!pwm5pin) if (!pwm5pin)
pwm5pin = regval & BIT(7); pwm5pin = regval & BIT(7);
fan6pin = regval & BIT(1);
pwm6pin = regval & BIT(0);
if (!fan5pin) if (!fan5pin)
fan5pin = regval_1b & BIT(5); fan5pin = regval_1b & BIT(5);
superio_select(sioreg, NCT6775_LD_12); superio_select(sioreg, NCT6775_LD_12);
regval_eb = superio_inb(sioreg, 0xeb); if (data->kind != nct6796) {
if (!fan5pin) int regval_eb = superio_inb(sioreg, 0xeb);
fan5pin = regval_eb & BIT(5);
if (!pwm5pin) if (!dsw_en) {
pwm5pin = (regval_eb & BIT(4)) && fan6pin = regval & BIT(1);
!(regval_2a & BIT(0)); pwm6pin = regval & BIT(0);
if (!fan6pin) }
fan6pin = regval_eb & BIT(3);
if (!pwm6pin) if (!fan5pin)
pwm6pin = regval_eb & BIT(2); fan5pin = regval_eb & BIT(5);
if (!pwm5pin)
pwm5pin = (regval_eb & BIT(4)) &&
!(regval_2a & BIT(0));
if (!fan6pin)
fan6pin = regval_eb & BIT(3);
if (!pwm6pin)
pwm6pin = regval_eb & BIT(2);
}
if (data->kind == nct6795 || data->kind == nct6796) {
int regval_ed = superio_inb(sioreg, 0xed);
if (!fan6pin)
fan6pin = (regval_2a & BIT(4)) &&
(!dsw_en ||
(dsw_en && (regval_ed & BIT(4))));
if (!pwm6pin)
pwm6pin = (regval_2a & BIT(3)) &&
(regval_ed & BIT(2));
}
if (data->kind == nct6796) {
int regval_1d = superio_inb(sioreg, 0x1d);
int regval_2b = superio_inb(sioreg, 0x2b);
fan7pin = !(regval_2b & BIT(2));
pwm7pin = !(regval_1d & (BIT(2) | BIT(3)));
}
break; break;
default: /* NCT6779D */ default: /* NCT6779D */
fan6pin = false;
pwm6pin = false;
break; break;
} }
...@@ -3493,11 +3556,11 @@ nct6775_check_fan_inputs(struct nct6775_data *data) ...@@ -3493,11 +3556,11 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
/* fan 1 and 2 (0x03) are always present */ /* fan 1 and 2 (0x03) are always present */
data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) | data->has_fan = 0x03 | (fan3pin << 2) | (fan4pin << 3) |
(fan5pin << 4) | (fan6pin << 5); (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) | data->has_fan_min = 0x03 | (fan3pin << 2) | (fan4min << 3) |
(fan5pin << 4); (fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) | data->has_pwm = 0x03 | (pwm3pin << 2) | (pwm4pin << 3) |
(pwm5pin << 4) | (pwm6pin << 5); (pwm5pin << 4) | (pwm6pin << 5) | (pwm7pin << 6);
} }
static void add_temp_sensors(struct nct6775_data *data, const u16 *regp, static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
...@@ -3856,8 +3919,9 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3856,8 +3919,9 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796:
data->in_num = 15; data->in_num = 15;
data->pwm_num = 6; data->pwm_num = (data->kind == nct6796) ? 7 : 6;
data->auto_pwm_num = 4; data->auto_pwm_num = 4;
data->has_fan_div = false; data->has_fan_div = false;
data->temp_fixed_num = 6; data->temp_fixed_num = 6;
...@@ -3891,6 +3955,10 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3891,6 +3955,10 @@ static int nct6775_probe(struct platform_device *pdev)
data->temp_label = nct6795_temp_label; data->temp_label = nct6795_temp_label;
data->temp_mask = NCT6795_TEMP_MASK; data->temp_mask = NCT6795_TEMP_MASK;
break; break;
case nct6796:
data->temp_label = nct6796_temp_label;
data->temp_mask = NCT6796_TEMP_MASK;
break;
} }
data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_CONFIG = NCT6775_REG_CONFIG;
...@@ -4159,6 +4227,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -4159,6 +4227,7 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796:
break; break;
} }
...@@ -4193,6 +4262,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -4193,6 +4262,7 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795: case nct6795:
case nct6796:
tmp |= 0x7e; tmp |= 0x7e;
break; break;
} }
...@@ -4291,7 +4361,8 @@ static int __maybe_unused nct6775_resume(struct device *dev) ...@@ -4291,7 +4361,8 @@ static int __maybe_unused nct6775_resume(struct device *dev)
superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable); superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
if (data->kind == nct6791 || data->kind == nct6792 || if (data->kind == nct6791 || data->kind == nct6792 ||
data->kind == nct6793 || data->kind == nct6795) data->kind == nct6793 || data->kind == nct6795 ||
data->kind == nct6796)
nct6791_enable_io_mapping(sioreg); nct6791_enable_io_mapping(sioreg);
superio_exit(sioreg); superio_exit(sioreg);
...@@ -4391,6 +4462,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) ...@@ -4391,6 +4462,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
case SIO_NCT6795_ID: case SIO_NCT6795_ID:
sio_data->kind = nct6795; sio_data->kind = nct6795;
break; break;
case SIO_NCT6796_ID:
sio_data->kind = nct6796;
break;
default: default:
if (val != 0xffff) if (val != 0xffff)
pr_debug("unsupported chip ID: 0x%04x\n", val); pr_debug("unsupported chip ID: 0x%04x\n", val);
...@@ -4417,7 +4491,8 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) ...@@ -4417,7 +4491,8 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
} }
if (sio_data->kind == nct6791 || sio_data->kind == nct6792 || if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
sio_data->kind == nct6793 || sio_data->kind == nct6795) sio_data->kind == nct6793 || sio_data->kind == nct6795 ||
sio_data->kind == nct6796)
nct6791_enable_io_mapping(sioaddr); nct6791_enable_io_mapping(sioaddr);
superio_exit(sioaddr); superio_exit(sioaddr);
......
...@@ -31,8 +31,8 @@ config SENSORS_ADM1275 ...@@ -31,8 +31,8 @@ config SENSORS_ADM1275
default n default n
help help
If you say yes here you get hardware monitoring support for Analog If you say yes here you get hardware monitoring support for Analog
Devices ADM1075, ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294 Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1293,
Hot-Swap Controller and Digital Power Monitors. and ADM1294 Hot-Swap Controller and Digital Power Monitors.
This driver can also be built as a module. If so, the module will This driver can also be built as a module. If so, the module will
be called adm1275. be called adm1275.
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* and Digital Power Monitor * and Digital Power Monitor
* *
* Copyright (c) 2011 Ericsson AB. * Copyright (c) 2011 Ericsson AB.
* Copyright (c) 2018 Guenter Roeck
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -24,7 +25,7 @@ ...@@ -24,7 +25,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include "pmbus.h" #include "pmbus.h"
enum chips { adm1075, adm1275, adm1276, adm1278, adm1293, adm1294 }; enum chips { adm1075, adm1272, adm1275, adm1276, adm1278, adm1293, adm1294 };
#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0) #define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0)
#define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5) #define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5)
...@@ -41,6 +42,8 @@ enum chips { adm1075, adm1275, adm1276, adm1278, adm1293, adm1294 }; ...@@ -41,6 +42,8 @@ enum chips { adm1075, adm1275, adm1276, adm1278, adm1293, adm1294 };
#define ADM1075_IRANGE_25 BIT(3) #define ADM1075_IRANGE_25 BIT(3)
#define ADM1075_IRANGE_MASK (BIT(3) | BIT(4)) #define ADM1075_IRANGE_MASK (BIT(3) | BIT(4))
#define ADM1272_IRANGE BIT(0)
#define ADM1278_TEMP1_EN BIT(3) #define ADM1278_TEMP1_EN BIT(3)
#define ADM1278_VIN_EN BIT(2) #define ADM1278_VIN_EN BIT(2)
#define ADM1278_VOUT_EN BIT(1) #define ADM1278_VOUT_EN BIT(1)
...@@ -105,6 +108,19 @@ static const struct coefficients adm1075_coefficients[] = { ...@@ -105,6 +108,19 @@ static const struct coefficients adm1075_coefficients[] = {
[4] = { 4279, 0, -1 }, /* power, irange50 */ [4] = { 4279, 0, -1 }, /* power, irange50 */
}; };
static const struct coefficients adm1272_coefficients[] = {
[0] = { 6770, 0, -2 }, /* voltage, vrange 60V */
[1] = { 4062, 0, -2 }, /* voltage, vrange 100V */
[2] = { 1326, 20480, -1 }, /* current, vsense range 15mV */
[3] = { 663, 20480, -1 }, /* current, vsense range 30mV */
[4] = { 3512, 0, -2 }, /* power, vrange 60V, irange 15mV */
[5] = { 21071, 0, -3 }, /* power, vrange 100V, irange 15mV */
[6] = { 17561, 0, -3 }, /* power, vrange 60V, irange 30mV */
[7] = { 10535, 0, -3 }, /* power, vrange 100V, irange 30mV */
[8] = { 42, 31871, -1 }, /* temperature */
};
static const struct coefficients adm1275_coefficients[] = { static const struct coefficients adm1275_coefficients[] = {
[0] = { 19199, 0, -2 }, /* voltage, vrange set */ [0] = { 19199, 0, -2 }, /* voltage, vrange set */
[1] = { 6720, 0, -1 }, /* voltage, vrange not set */ [1] = { 6720, 0, -1 }, /* voltage, vrange not set */
...@@ -154,7 +170,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) ...@@ -154,7 +170,7 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
const struct adm1275_data *data = to_adm1275_data(info); const struct adm1275_data *data = to_adm1275_data(info);
int ret = 0; int ret = 0;
if (page) if (page > 0)
return -ENXIO; return -ENXIO;
switch (reg) { switch (reg) {
...@@ -240,7 +256,7 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, ...@@ -240,7 +256,7 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
const struct adm1275_data *data = to_adm1275_data(info); const struct adm1275_data *data = to_adm1275_data(info);
int ret; int ret;
if (page) if (page > 0)
return -ENXIO; return -ENXIO;
switch (reg) { switch (reg) {
...@@ -335,6 +351,7 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) ...@@ -335,6 +351,7 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
static const struct i2c_device_id adm1275_id[] = { static const struct i2c_device_id adm1275_id[] = {
{ "adm1075", adm1075 }, { "adm1075", adm1075 },
{ "adm1272", adm1272 },
{ "adm1275", adm1275 }, { "adm1275", adm1275 },
{ "adm1276", adm1276 }, { "adm1276", adm1276 },
{ "adm1278", adm1278 }, { "adm1278", adm1278 },
...@@ -451,6 +468,54 @@ static int adm1275_probe(struct i2c_client *client, ...@@ -451,6 +468,54 @@ static int adm1275_probe(struct i2c_client *client,
info->func[0] |= info->func[0] |=
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
break; break;
case adm1272:
data->have_vout = true;
data->have_pin_max = true;
data->have_temp_max = true;
coefficients = adm1272_coefficients;
vindex = (config & ADM1275_VRANGE) ? 1 : 0;
cindex = (config & ADM1272_IRANGE) ? 3 : 2;
/* pindex depends on the combination of the above */
switch (config & (ADM1275_VRANGE | ADM1272_IRANGE)) {
case 0:
default:
pindex = 4;
break;
case ADM1275_VRANGE:
pindex = 5;
break;
case ADM1272_IRANGE:
pindex = 6;
break;
case ADM1275_VRANGE | ADM1272_IRANGE:
pindex = 7;
break;
}
tindex = 8;
info->func[0] |= PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT |
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
/* Enable VOUT if not enabled (it is disabled by default) */
if (!(config & ADM1278_VOUT_EN)) {
config |= ADM1278_VOUT_EN;
ret = i2c_smbus_write_byte_data(client,
ADM1275_PMON_CONFIG,
config);
if (ret < 0) {
dev_err(&client->dev,
"Failed to enable VOUT monitoring\n");
return -ENODEV;
}
}
if (config & ADM1278_TEMP1_EN)
info->func[0] |=
PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
if (config & ADM1278_VIN_EN)
info->func[0] |= PMBUS_HAVE_VIN;
break;
case adm1275: case adm1275:
if (device_config & ADM1275_IOUT_WARN2_SELECT) if (device_config & ADM1275_IOUT_WARN2_SELECT)
data->have_oc_fault = true; data->have_oc_fault = true;
......
...@@ -45,7 +45,7 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg) ...@@ -45,7 +45,7 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
{ {
int ret; int ret;
if (page) if (page > 0)
return -ENXIO; return -ENXIO;
switch (reg) { switch (reg) {
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/debugfs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
...@@ -27,6 +28,8 @@ ...@@ -27,6 +28,8 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/pmbus.h> #include <linux/pmbus.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include "pmbus.h" #include "pmbus.h"
enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 }; enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
...@@ -35,8 +38,19 @@ enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 }; ...@@ -35,8 +38,19 @@ enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
#define UCD9000_NUM_PAGES 0xd6 #define UCD9000_NUM_PAGES 0xd6
#define UCD9000_FAN_CONFIG_INDEX 0xe7 #define UCD9000_FAN_CONFIG_INDEX 0xe7
#define UCD9000_FAN_CONFIG 0xe8 #define UCD9000_FAN_CONFIG 0xe8
#define UCD9000_MFR_STATUS 0xf3
#define UCD9000_GPIO_SELECT 0xfa
#define UCD9000_GPIO_CONFIG 0xfb
#define UCD9000_DEVICE_ID 0xfd #define UCD9000_DEVICE_ID 0xfd
/* GPIO CONFIG bits */
#define UCD9000_GPIO_CONFIG_ENABLE BIT(0)
#define UCD9000_GPIO_CONFIG_OUT_ENABLE BIT(1)
#define UCD9000_GPIO_CONFIG_OUT_VALUE BIT(2)
#define UCD9000_GPIO_CONFIG_STATUS BIT(3)
#define UCD9000_GPIO_INPUT 0
#define UCD9000_GPIO_OUTPUT 1
#define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07) #define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07)
#define UCD9000_MON_PAGE(x) ((x) & 0x0f) #define UCD9000_MON_PAGE(x) ((x) & 0x0f)
...@@ -47,12 +61,29 @@ enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 }; ...@@ -47,12 +61,29 @@ enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
#define UCD9000_NUM_FAN 4 #define UCD9000_NUM_FAN 4
#define UCD9000_GPIO_NAME_LEN 16
#define UCD9090_NUM_GPIOS 23
#define UCD901XX_NUM_GPIOS 26
#define UCD90910_NUM_GPIOS 26
#define UCD9000_DEBUGFS_NAME_LEN 24
#define UCD9000_GPI_COUNT 8
struct ucd9000_data { struct ucd9000_data {
u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX];
struct pmbus_driver_info info; struct pmbus_driver_info info;
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio;
#endif
struct dentry *debugfs;
}; };
#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) #define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info)
struct ucd9000_debugfs_entry {
struct i2c_client *client;
u8 index;
};
static int ucd9000_get_fan_config(struct i2c_client *client, int fan) static int ucd9000_get_fan_config(struct i2c_client *client, int fan)
{ {
int fan_config = 0; int fan_config = 0;
...@@ -149,6 +180,312 @@ static const struct of_device_id ucd9000_of_match[] = { ...@@ -149,6 +180,312 @@ static const struct of_device_id ucd9000_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, ucd9000_of_match); MODULE_DEVICE_TABLE(of, ucd9000_of_match);
#ifdef CONFIG_GPIOLIB
static int ucd9000_gpio_read_config(struct i2c_client *client,
unsigned int offset)
{
int ret;
/* No page set required */
ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_SELECT, offset);
if (ret < 0)
return ret;
return i2c_smbus_read_byte_data(client, UCD9000_GPIO_CONFIG);
}
static int ucd9000_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct i2c_client *client = gpiochip_get_data(gc);
int ret;
ret = ucd9000_gpio_read_config(client, offset);
if (ret < 0)
return ret;
return !!(ret & UCD9000_GPIO_CONFIG_STATUS);
}
static void ucd9000_gpio_set(struct gpio_chip *gc, unsigned int offset,
int value)
{
struct i2c_client *client = gpiochip_get_data(gc);
int ret;
ret = ucd9000_gpio_read_config(client, offset);
if (ret < 0) {
dev_dbg(&client->dev, "failed to read GPIO %d config: %d\n",
offset, ret);
return;
}
if (value) {
if (ret & UCD9000_GPIO_CONFIG_STATUS)
return;
ret |= UCD9000_GPIO_CONFIG_STATUS;
} else {
if (!(ret & UCD9000_GPIO_CONFIG_STATUS))
return;
ret &= ~UCD9000_GPIO_CONFIG_STATUS;
}
ret |= UCD9000_GPIO_CONFIG_ENABLE;
/* Page set not required */
ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, ret);
if (ret < 0) {
dev_dbg(&client->dev, "Failed to write GPIO %d config: %d\n",
offset, ret);
return;
}
ret &= ~UCD9000_GPIO_CONFIG_ENABLE;
ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, ret);
if (ret < 0)
dev_dbg(&client->dev, "Failed to write GPIO %d config: %d\n",
offset, ret);
}
static int ucd9000_gpio_get_direction(struct gpio_chip *gc,
unsigned int offset)
{
struct i2c_client *client = gpiochip_get_data(gc);
int ret;
ret = ucd9000_gpio_read_config(client, offset);
if (ret < 0)
return ret;
return !(ret & UCD9000_GPIO_CONFIG_OUT_ENABLE);
}
static int ucd9000_gpio_set_direction(struct gpio_chip *gc,
unsigned int offset, bool direction_out,
int requested_out)
{
struct i2c_client *client = gpiochip_get_data(gc);
int ret, config, out_val;
ret = ucd9000_gpio_read_config(client, offset);
if (ret < 0)
return ret;
if (direction_out) {
out_val = requested_out ? UCD9000_GPIO_CONFIG_OUT_VALUE : 0;
if (ret & UCD9000_GPIO_CONFIG_OUT_ENABLE) {
if ((ret & UCD9000_GPIO_CONFIG_OUT_VALUE) == out_val)
return 0;
} else {
ret |= UCD9000_GPIO_CONFIG_OUT_ENABLE;
}
if (out_val)
ret |= UCD9000_GPIO_CONFIG_OUT_VALUE;
else
ret &= ~UCD9000_GPIO_CONFIG_OUT_VALUE;
} else {
if (!(ret & UCD9000_GPIO_CONFIG_OUT_ENABLE))
return 0;
ret &= ~UCD9000_GPIO_CONFIG_OUT_ENABLE;
}
ret |= UCD9000_GPIO_CONFIG_ENABLE;
config = ret;
/* Page set not required */
ret = i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, config);
if (ret < 0)
return ret;
config &= ~UCD9000_GPIO_CONFIG_ENABLE;
return i2c_smbus_write_byte_data(client, UCD9000_GPIO_CONFIG, config);
}
static int ucd9000_gpio_direction_input(struct gpio_chip *gc,
unsigned int offset)
{
return ucd9000_gpio_set_direction(gc, offset, UCD9000_GPIO_INPUT, 0);
}
static int ucd9000_gpio_direction_output(struct gpio_chip *gc,
unsigned int offset, int val)
{
return ucd9000_gpio_set_direction(gc, offset, UCD9000_GPIO_OUTPUT,
val);
}
static void ucd9000_probe_gpio(struct i2c_client *client,
const struct i2c_device_id *mid,
struct ucd9000_data *data)
{
int rc;
switch (mid->driver_data) {
case ucd9090:
data->gpio.ngpio = UCD9090_NUM_GPIOS;
break;
case ucd90120:
case ucd90124:
case ucd90160:
data->gpio.ngpio = UCD901XX_NUM_GPIOS;
break;
case ucd90910:
data->gpio.ngpio = UCD90910_NUM_GPIOS;
break;
default:
return; /* GPIO support is optional. */
}
/*
* Pinmux support has not been added to the new gpio_chip.
* This support should be added when possible given the mux
* behavior of these IO devices.
*/
data->gpio.label = client->name;
data->gpio.get_direction = ucd9000_gpio_get_direction;
data->gpio.direction_input = ucd9000_gpio_direction_input;
data->gpio.direction_output = ucd9000_gpio_direction_output;
data->gpio.get = ucd9000_gpio_get;
data->gpio.set = ucd9000_gpio_set;
data->gpio.can_sleep = true;
data->gpio.base = -1;
data->gpio.parent = &client->dev;
rc = devm_gpiochip_add_data(&client->dev, &data->gpio, client);
if (rc)
dev_warn(&client->dev, "Could not add gpiochip: %d\n", rc);
}
#else
static void ucd9000_probe_gpio(struct i2c_client *client,
const struct i2c_device_id *mid,
struct ucd9000_data *data)
{
}
#endif /* CONFIG_GPIOLIB */
#ifdef CONFIG_DEBUG_FS
static int ucd9000_get_mfr_status(struct i2c_client *client, u8 *buffer)
{
int ret = pmbus_set_page(client, 0);
if (ret < 0)
return ret;
return i2c_smbus_read_block_data(client, UCD9000_MFR_STATUS, buffer);
}
static int ucd9000_debugfs_show_mfr_status_bit(void *data, u64 *val)
{
struct ucd9000_debugfs_entry *entry = data;
struct i2c_client *client = entry->client;
u8 buffer[I2C_SMBUS_BLOCK_MAX];
int ret;
ret = ucd9000_get_mfr_status(client, buffer);
if (ret < 0)
return ret;
/*
* Attribute only created for devices with gpi fault bits at bits
* 16-23, which is the second byte of the response.
*/
*val = !!(buffer[1] & BIT(entry->index));
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(ucd9000_debugfs_mfr_status_bit,
ucd9000_debugfs_show_mfr_status_bit, NULL, "%1lld\n");
static ssize_t ucd9000_debugfs_read_mfr_status(struct file *file,
char __user *buf, size_t count,
loff_t *ppos)
{
struct i2c_client *client = file->private_data;
u8 buffer[I2C_SMBUS_BLOCK_MAX];
char str[(I2C_SMBUS_BLOCK_MAX * 2) + 2];
char *res;
int rc;
rc = ucd9000_get_mfr_status(client, buffer);
if (rc < 0)
return rc;
res = bin2hex(str, buffer, min(rc, I2C_SMBUS_BLOCK_MAX));
*res++ = '\n';
*res = 0;
return simple_read_from_buffer(buf, count, ppos, str, res - str);
}
static const struct file_operations ucd9000_debugfs_show_mfr_status_fops = {
.llseek = noop_llseek,
.read = ucd9000_debugfs_read_mfr_status,
.open = simple_open,
};
static int ucd9000_init_debugfs(struct i2c_client *client,
const struct i2c_device_id *mid,
struct ucd9000_data *data)
{
struct dentry *debugfs;
struct ucd9000_debugfs_entry *entries;
int i;
char name[UCD9000_DEBUGFS_NAME_LEN];
debugfs = pmbus_get_debugfs_dir(client);
if (!debugfs)
return -ENOENT;
data->debugfs = debugfs_create_dir(client->name, debugfs);
if (!data->debugfs)
return -ENOENT;
/*
* Of the chips this driver supports, only the UCD9090, UCD90160,
* and UCD90910 report GPI faults in their MFR_STATUS register, so only
* create the GPI fault debugfs attributes for those chips.
*/
if (mid->driver_data == ucd9090 || mid->driver_data == ucd90160 ||
mid->driver_data == ucd90910) {
entries = devm_kzalloc(&client->dev,
sizeof(*entries) * UCD9000_GPI_COUNT,
GFP_KERNEL);
if (!entries)
return -ENOMEM;
for (i = 0; i < UCD9000_GPI_COUNT; i++) {
entries[i].client = client;
entries[i].index = i;
scnprintf(name, UCD9000_DEBUGFS_NAME_LEN,
"gpi%d_alarm", i + 1);
debugfs_create_file(name, 0444, data->debugfs,
&entries[i],
&ucd9000_debugfs_mfr_status_bit);
}
}
scnprintf(name, UCD9000_DEBUGFS_NAME_LEN, "mfr_status");
debugfs_create_file(name, 0444, data->debugfs, client,
&ucd9000_debugfs_show_mfr_status_fops);
return 0;
}
#else
static int ucd9000_init_debugfs(struct i2c_client *client,
const struct i2c_device_id *mid,
struct ucd9000_data *data)
{
return 0;
}
#endif /* CONFIG_DEBUG_FS */
static int ucd9000_probe(struct i2c_client *client, static int ucd9000_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
...@@ -263,7 +600,18 @@ static int ucd9000_probe(struct i2c_client *client, ...@@ -263,7 +600,18 @@ static int ucd9000_probe(struct i2c_client *client,
| PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34; | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34;
} }
return pmbus_do_probe(client, mid, info); ucd9000_probe_gpio(client, mid, data);
ret = pmbus_do_probe(client, mid, info);
if (ret)
return ret;
ret = ucd9000_init_debugfs(client, mid, data);
if (ret)
dev_warn(&client->dev, "Failed to register debugfs: %d\n",
ret);
return 0;
} }
/* This is the driver that will be inserted */ /* This is the driver that will be inserted */
......
...@@ -16,8 +16,7 @@ ...@@ -16,8 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
* *
* Data sheet available (5/2010) at * Data sheet available at http://www.sensirion.com/file/datasheet_sht21
* http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf
*/ */
#include <linux/module.h> #include <linux/module.h>
......
...@@ -136,20 +136,24 @@ static int via_cputemp_probe(struct platform_device *pdev) ...@@ -136,20 +136,24 @@ static int via_cputemp_probe(struct platform_device *pdev)
data->id = pdev->id; data->id = pdev->id;
data->name = "via_cputemp"; data->name = "via_cputemp";
switch (c->x86_model) { if (c->x86 == 7) {
case 0xA:
/* C7 A */
case 0xD:
/* C7 D */
data->msr_temp = 0x1169;
data->msr_vid = 0x198;
break;
case 0xF:
/* Nano */
data->msr_temp = 0x1423; data->msr_temp = 0x1423;
break; } else {
default: switch (c->x86_model) {
return -ENODEV; case 0xA:
/* C7 A */
case 0xD:
/* C7 D */
data->msr_temp = 0x1169;
data->msr_vid = 0x198;
break;
case 0xF:
/* Nano */
data->msr_temp = 0x1423;
break;
default:
return -ENODEV;
}
} }
/* test if we can access the TEMPERATURE MSR */ /* test if we can access the TEMPERATURE MSR */
...@@ -283,6 +287,7 @@ static const struct x86_cpu_id __initconst cputemp_ids[] = { ...@@ -283,6 +287,7 @@ static const struct x86_cpu_id __initconst cputemp_ids[] = {
{ X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */ { X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */
{ X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */ { X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */
{ X86_VENDOR_CENTAUR, 6, 0xf, }, /* Nano */ { X86_VENDOR_CENTAUR, 6, 0xf, }, /* Nano */
{ X86_VENDOR_CENTAUR, 7, X86_MODEL_ANY, },
{} {}
}; };
MODULE_DEVICE_TABLE(x86cpu, cputemp_ids); MODULE_DEVICE_TABLE(x86cpu, cputemp_ids);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment