mirror of https://gitee.com/openkylin/linux.git
hwmon updates for v4.17
- Added chip support: new centaur CPUs, ADM1272, NCT6796D - ucd9000: added debugfs attributes, gpio support - Cleanup and minor bug fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJay6EdAAoJEMsfJm/On5mBFtAP/jNsoEEjfibtIl7UN0cZm1Ec f5awcKr0WM4BTYxiBDJkM4KrugODOsOVlfQQakulmarsF4gKBpH8I5XKRGc2Wny/ DMD/nPsu6laLoFwaIhIiOlwerc7ppQHOe9OlwbBvVRptG8t710479JC68O1XDpqu tP/C5+QlmIOs+HXgDXBE96xjPxfi1emYxvgzIH/Q2nf0Sd1GKQVYlbIF94xeZBDg cp1Sv7XeoWxsb4QwUWL3YbwCc8kABgVHmjogZsyFd6fyIRM8bi+RJGIheawhT7xr iaQ2iihW1nvdPHLAssqEG5KaJGpHobcrRm1Wy/lCWfiiLI+ortl5Xn4b9fZCmM+W zKK1QhAKoe26QdsrHBdgjprldpmlfUz+wnkFILu3dQfvDugo75t3B9W62faoqsvh CqRxLwolFf+2yOepmB9uXXuv+9vf41P2HP1axhlkJkcQVRby+f52va9btgi5z64a 56OWzCqY5ESWnC+8Tm/w7rf5w28iWXAKmi0+GqIBDJn0jsTw+MfERa2ruR5omeTh Eo0FkwzcgGmshhkk/q+ffNooqEvV5Ry4CSq7dgxNTB8Ri65zxW7Hnhp8yb9WN+MP LMC0WSjZ/y6CPi2lNU96bakdT+LPB/HFEYTTEEsDSFGbrDkcHQn6cVgwGbDZYlgw DPDhuJAgyQJCvce7TFCu =M6YK -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
71219b3494
|
@ -6,6 +6,10 @@ Supported chips:
|
|||
Prefix: 'adm1075'
|
||||
Addresses scanned: -
|
||||
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
|
||||
Prefix: 'adm1275'
|
||||
Addresses scanned: -
|
||||
|
@ -29,11 +33,11 @@ Author: Guenter Roeck <linux@roeck-us.net>
|
|||
Description
|
||||
-----------
|
||||
|
||||
This driver supports hardware monitoring for Analog Devices ADM1075, ADM1275,
|
||||
ADM1276, ADM1278, ADM1293, and ADM1294 Hot-Swap Controller and Digital
|
||||
Power Monitors.
|
||||
This driver supports hardware monitoring for Analog Devices ADM1075, ADM1272,
|
||||
ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294 Hot-Swap Controller and
|
||||
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
|
||||
a live backplane. They also feature current and voltage readback via an
|
||||
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.
|
|||
power1_input_highest Highest observed input power.
|
||||
power1_reset_history Write any value to reset history.
|
||||
|
||||
Power attributes are supported on ADM1075, ADM1276,
|
||||
ADM1293, and ADM1294.
|
||||
Power attributes are supported on ADM1075, ADM1272,
|
||||
ADM1276, ADM1293, and ADM1294.
|
||||
|
||||
temp1_input Chip temperature.
|
||||
Temperature attributes are only available on ADM1278.
|
||||
temp1_max Maximum chip temperature.
|
||||
temp1_max_alarm Temperature alarm.
|
||||
temp1_crit Critical chip temperature.
|
||||
|
@ -112,4 +115,5 @@ temp1_crit_alarm Critical temperature high alarm.
|
|||
temp1_highest Highest observed temperature.
|
||||
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:
|
|||
Addresses scanned: none, force parameter needed
|
||||
Datasheet: http://www.national.com/pf/LM/LM76.html
|
||||
* Maxim MAX6633/MAX6634/MAX6635
|
||||
Prefix: 'lm92'
|
||||
Addresses scanned: I2C 0x48 - 0x4b
|
||||
MAX6633 with address in 0x40 - 0x47, 0x4c - 0x4f needs force parameter
|
||||
and MAX6634 with address in 0x4c - 0x4f needs force parameter
|
||||
Prefix: 'max6635'
|
||||
Addresses scanned: none, force parameter needed
|
||||
Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3074
|
||||
|
||||
Authors:
|
||||
|
|
|
@ -36,6 +36,14 @@ Supported chips:
|
|||
Prefix: 'nct6793'
|
||||
Addresses scanned: ISA address retrieved from Super I/O registers
|
||||
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:
|
||||
Guenter Roeck <linux@roeck-us.net>
|
||||
|
@ -88,10 +96,10 @@ The mode works for fan1-fan5.
|
|||
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)
|
||||
|
||||
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)
|
||||
* 1 Manual mode, write to pwm[0-5] any value 0-255
|
||||
* 2 "Thermal Cruise" mode
|
||||
|
@ -99,16 +107,16 @@ pwm[1-5]_enable - this file controls mode of fan/temperature control:
|
|||
* 4 "Smart Fan III" mode (NCT6775F only)
|
||||
* 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
|
||||
* 1 PWM output
|
||||
|
||||
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.
|
||||
pwm[1-5]_weight_temp_sel
|
||||
pwm[1-7]_weight_temp_sel
|
||||
Secondary temperature source. Value is temperature
|
||||
sensor index. For example, select '1' for temp1_input.
|
||||
Set to 0 to disable secondary temperature control.
|
||||
|
@ -116,16 +124,16 @@ pwm[1-5]_weight_temp_sel
|
|||
If secondary temperature functionality is enabled, it is controlled with the
|
||||
following attributes.
|
||||
|
||||
pwm[1-5]_weight_duty_step
|
||||
pwm[1-7]_weight_duty_step
|
||||
Duty step size.
|
||||
pwm[1-5]_weight_temp_step
|
||||
pwm[1-7]_weight_temp_step
|
||||
Temperature step size. With each step over
|
||||
temp_step_base, the value of weight_duty_step is added
|
||||
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
|
||||
in.
|
||||
pwm[1-5]_weight_temp_step_tol
|
||||
pwm[1-7]_weight_temp_step_tol
|
||||
Temperature step tolerance.
|
||||
|
||||
Thermal Cruise mode (2)
|
||||
|
@ -133,9 +141,9 @@ Thermal Cruise mode (2)
|
|||
|
||||
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)
|
||||
pwm[1-5]_temp_tolerance
|
||||
pwm[1-7]_temp_tolerance
|
||||
Target temperature tolerance, unit millidegree Celsius
|
||||
|
||||
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
|
|||
temperature is lower than desired), using the following limits and time
|
||||
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.
|
||||
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
|
||||
stop if the temperature is below the defined range.
|
||||
pwm[1-5]_step_up_time milliseconds before fan speed is increased
|
||||
pwm[1-5]_step_down_time milliseconds before fan speed is decreased
|
||||
pwm[1-5]_stop_time how many milliseconds must elapse to switch
|
||||
pwm[1-7]_step_up_time milliseconds before fan speed is increased
|
||||
pwm[1-7]_step_down_time milliseconds before fan speed is decreased
|
||||
pwm[1-7]_stop_time how many milliseconds must elapse to switch
|
||||
corresponding fan off (when the temperature was below
|
||||
defined range).
|
||||
|
||||
|
@ -159,8 +167,8 @@ Speed Cruise mode (3)
|
|||
|
||||
This modes tries to keep the fan speed constant.
|
||||
|
||||
fan[1-5]_target Target fan speed
|
||||
fan[1-5]_tolerance
|
||||
fan[1-7]_target Target fan speed
|
||||
fan[1-7]_tolerance
|
||||
Target speed tolerance
|
||||
|
||||
|
||||
|
@ -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
|
||||
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
|
||||
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.
|
||||
pwm[1-5]_temp_tolerance
|
||||
pwm[1-7]_temp_tolerance
|
||||
Temperature tolerance, unit millidegree Celsius
|
||||
pwm[1-5]_crit_temp_tolerance
|
||||
pwm[1-7]_crit_temp_tolerance
|
||||
Temperature tolerance for critical temperature,
|
||||
unit millidegree Celsius
|
||||
|
||||
pwm[1-5]_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_up_time milliseconds before fan speed is increased
|
||||
pwm[1-7]_step_down_time milliseconds before fan speed is decreased
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
|
|
@ -6,13 +6,13 @@ Supported chips:
|
|||
Prefix: 'sht21'
|
||||
Addresses scanned: none
|
||||
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
|
||||
Prefix: 'sht21'
|
||||
Prefix: 'sht25'
|
||||
Addresses scanned: none
|
||||
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:
|
||||
Urs Fleisch <urs.fleisch@sensirion.com>
|
||||
|
|
|
@ -5,7 +5,7 @@ Supported chips:
|
|||
* Sensirion SHT3x-DIS
|
||||
Prefix: 'sht3x'
|
||||
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:
|
||||
David Frey <david.frey@sensirion.com>
|
||||
|
|
|
@ -1231,8 +1231,9 @@ config SENSORS_NCT6775
|
|||
help
|
||||
If you say yes here you get support for the hardware monitoring
|
||||
functionality of the Nuvoton NCT6106D, NCT6775F, NCT6776F, NCT6779D,
|
||||
NCT6791D, NCT6792D, NCT6793D, and compatible Super-I/O chips. This
|
||||
driver replaces the w83627ehf driver for NCT6775F and NCT6776F.
|
||||
NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D, and compatible
|
||||
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
|
||||
will be called nct6775.
|
||||
|
|
|
@ -128,7 +128,6 @@ enum g762_regs {
|
|||
G762_REG_FAN_CMD2_GEAR_MODE_1)) >> 2))
|
||||
|
||||
struct g762_data {
|
||||
struct device *hwmon_dev;
|
||||
struct i2c_client *client;
|
||||
struct clk *clk;
|
||||
|
||||
|
@ -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
|
||||
* 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)
|
||||
{
|
||||
struct g762_data *data;
|
||||
|
@ -626,6 +633,7 @@ static int g762_of_clock_enable(struct i2c_client *client)
|
|||
data = i2c_get_clientdata(client);
|
||||
data->clk = clk;
|
||||
|
||||
devm_add_action(&client->dev, g762_of_clock_disable, data);
|
||||
return 0;
|
||||
|
||||
clk_unprep:
|
||||
|
@ -637,17 +645,6 @@ static int g762_of_clock_enable(struct i2c_client *client)
|
|||
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,
|
||||
const char *pname,
|
||||
int (*psetter)(struct device *dev,
|
||||
|
@ -698,8 +695,6 @@ static int g762_of_clock_enable(struct i2c_client *client)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void g762_of_clock_disable(struct i2c_client *client) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct g762_data *data;
|
||||
int ret;
|
||||
|
||||
|
@ -1080,35 +1076,15 @@ static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
return ret;
|
||||
ret = g762_of_prop_import(client);
|
||||
if (ret)
|
||||
goto clock_dis;
|
||||
return ret;
|
||||
/* ... or platform_data */
|
||||
ret = g762_pdata_prop_import(client);
|
||||
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);
|
||||
if (IS_ERR(data->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;
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
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),
|
||||
},
|
||||
.probe = g762_probe,
|
||||
.remove = g762_remove,
|
||||
.id_table = g762_id,
|
||||
};
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
*/
|
||||
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
|
||||
I2C_CLIENT_END };
|
||||
enum chips { lm92, max6635 };
|
||||
|
||||
/* The LM92 registers */
|
||||
#define LM92_REG_CONFIG 0x01 /* 8-bit, RW */
|
||||
|
@ -259,62 +260,6 @@ static void lm92_init_client(struct i2c_client *client)
|
|||
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[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
|
@ -348,8 +293,6 @@ static int lm92_detect(struct i2c_client *new_client,
|
|||
|
||||
if ((config & 0xe0) == 0x00 && man_id == 0x0180)
|
||||
pr_info("lm92: Found National Semiconductor LM92 chip\n");
|
||||
else if (max6635_check(new_client))
|
||||
pr_info("lm92: Found Maxim MAX6635 chip\n");
|
||||
else
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -387,8 +330,8 @@ static int lm92_probe(struct i2c_client *new_client,
|
|||
*/
|
||||
|
||||
static const struct i2c_device_id lm92_id[] = {
|
||||
{ "lm92", 0 },
|
||||
/* max6635 could be added here */
|
||||
{ "lm92", lm92 },
|
||||
{ "max6635", max6635 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm92_id);
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
* nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
|
||||
* nct6793d 15 6 6 2+6 0xd120 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
|
||||
* the number of directly connectable temperature sensors (second value).
|
||||
|
@ -68,7 +68,7 @@
|
|||
#define USE_ALTERNATE
|
||||
|
||||
enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
|
||||
nct6795 };
|
||||
nct6795, nct6796 };
|
||||
|
||||
/* used to set data->name = nct6775_device_names[data->sio_kind] */
|
||||
static const char * const nct6775_device_names[] = {
|
||||
|
@ -80,6 +80,7 @@ static const char * const nct6775_device_names[] = {
|
|||
"nct6792",
|
||||
"nct6793",
|
||||
"nct6795",
|
||||
"nct6796",
|
||||
};
|
||||
|
||||
static const char * const nct6775_sio_names[] __initconst = {
|
||||
|
@ -91,6 +92,7 @@ static const char * const nct6775_sio_names[] __initconst = {
|
|||
"NCT6792D",
|
||||
"NCT6793D",
|
||||
"NCT6795D",
|
||||
"NCT6796D",
|
||||
};
|
||||
|
||||
static unsigned short force_id;
|
||||
|
@ -125,6 +127,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
|
|||
#define SIO_NCT6792_ID 0xc910
|
||||
#define SIO_NCT6793_ID 0xd120
|
||||
#define SIO_NCT6795_ID 0xd350
|
||||
#define SIO_NCT6796_ID 0xd420
|
||||
#define SIO_ID_MASK 0xFFF0
|
||||
|
||||
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
|
||||
|
@ -201,7 +204,7 @@ superio_exit(int ioreg)
|
|||
#define NUM_REG_ALARM 7 /* Max number of alarm registers */
|
||||
#define NUM_REG_BEEP 5 /* Max number of beep registers */
|
||||
|
||||
#define NUM_FAN 6
|
||||
#define NUM_FAN 7
|
||||
|
||||
#define TEMP_SOURCE_VIRTUAL 0x1f
|
||||
|
||||
|
@ -272,26 +275,26 @@ static const u8 NCT6775_PWM_MODE_MASK[] = { 0x01, 0x02, 0x01 };
|
|||
/* Advanced Fan control, some values are common for all fans */
|
||||
|
||||
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[] = {
|
||||
0x102, 0x202, 0x302, 0x802, 0x902, 0xa02 };
|
||||
0x102, 0x202, 0x302, 0x802, 0x902, 0xa02, 0xb02 };
|
||||
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[] = {
|
||||
0x104, 0x204, 0x304, 0x804, 0x904, 0xa04 };
|
||||
0x104, 0x204, 0x304, 0x804, 0x904, 0xa04, 0xb04 };
|
||||
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[] = {
|
||||
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_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
|
||||
|
||||
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[] = {
|
||||
0x109, 0x209, 0x309, 0x809, 0x909, 0xa09 };
|
||||
0x109, 0x209, 0x309, 0x809, 0x909, 0xa09, 0xb09 };
|
||||
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_MIN[] = { 0x3b, 0x3c, 0x3d };
|
||||
|
@ -314,7 +317,7 @@ static const u16 NCT6775_REG_TEMP_SOURCE[ARRAY_SIZE(NCT6775_REG_TEMP)] = {
|
|||
0x621, 0x622, 0x623, 0x624, 0x625, 0x626 };
|
||||
|
||||
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[] = {
|
||||
0x139, 0x239, 0x339, 0x839, 0x939, 0xa39 };
|
||||
|
@ -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_AUTO_TEMP[] = {
|
||||
0x121, 0x221, 0x321, 0x821, 0x921, 0xa21 };
|
||||
0x121, 0x221, 0x321, 0x821, 0x921, 0xa21, 0xb21 };
|
||||
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_PWM(data, nr, p) ((data)->REG_AUTO_PWM[nr] + (p))
|
||||
|
@ -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_TEMP[] = {
|
||||
0x135, 0x235, 0x335, 0x835, 0x935, 0xa35 };
|
||||
0x135, 0x235, 0x335, 0x835, 0x935, 0xa35, 0xb35 };
|
||||
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[] = {
|
||||
"",
|
||||
|
@ -414,13 +417,15 @@ static const s8 NCT6776_BEEP_BITS[] = {
|
|||
30, 31 }; /* intrusion0, intrusion1 */
|
||||
|
||||
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_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_PULSES[] = { 0x644, 0x645, 0x646, 0, 0 };
|
||||
static const u16 NCT6776_REG_FAN_MIN[] = {
|
||||
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[] = {
|
||||
0x13e, 0x23e, 0x33e, 0x83e, 0x93e, 0xa3e };
|
||||
|
@ -495,15 +500,15 @@ static const s8 NCT6779_BEEP_BITS[] = {
|
|||
30, 31 }; /* intrusion0, intrusion1 */
|
||||
|
||||
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[] = {
|
||||
0x644, 0x645, 0x646, 0x647, 0x648, 0x649 };
|
||||
0x644, 0x645, 0x646, 0x647, 0x648, 0x649, 0 };
|
||||
|
||||
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
|
||||
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_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b };
|
||||
|
@ -570,12 +575,12 @@ static const u16 NCT6779_REG_TEMP_CRIT[32] = {
|
|||
|
||||
#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_STEP[6] = { 0, 0x23a };
|
||||
static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b };
|
||||
static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c };
|
||||
static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d };
|
||||
static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e };
|
||||
static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[NUM_FAN] = { 0, 0x239 };
|
||||
static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[NUM_FAN] = { 0, 0x23a };
|
||||
static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[NUM_FAN] = { 0, 0x23b };
|
||||
static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[NUM_FAN] = { 0, 0x23c };
|
||||
static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[NUM_FAN] = { 0, 0x23d };
|
||||
static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[NUM_FAN] = { 0, 0x23e };
|
||||
|
||||
static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = {
|
||||
0x459, 0x45A, 0x45B, 0x568, 0x45D };
|
||||
|
@ -707,6 +712,43 @@ static const char *const nct6795_temp_label[] = {
|
|||
|
||||
#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 */
|
||||
|
||||
#define NCT6106_REG_VBAT 0x318
|
||||
|
@ -1231,11 +1273,13 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
|
|||
case nct6792:
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
|
||||
((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
|
||||
reg == 0x402 ||
|
||||
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 == 0x7b || reg == 0x7d;
|
||||
}
|
||||
|
@ -1469,7 +1513,7 @@ static void nct6775_update_pwm(struct device *dev)
|
|||
duty_is_dc = data->REG_PWM_MODE[i] &&
|
||||
(nct6775_read_value(data, data->REG_PWM_MODE[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]);
|
||||
for (j = 0; j < ARRAY_SIZE(data->REG_PWM); j++) {
|
||||
|
@ -1584,6 +1628,7 @@ static void nct6775_update_pwm_limits(struct device *dev)
|
|||
case nct6792:
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
reg = nct6775_read_value(data,
|
||||
data->REG_CRITICAL_PWM_ENABLE[i]);
|
||||
if (reg & data->CRITICAL_PWM_ENABLE_MASK)
|
||||
|
@ -2092,6 +2137,8 @@ static umode_t nct6775_fan_is_visible(struct kobject *kobj,
|
|||
return 0;
|
||||
if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
|
||||
return 0;
|
||||
if (nr == 3 && !data->REG_FAN_PULSES[fan])
|
||||
return 0;
|
||||
if (nr == 4 && !(data->has_fan_min & BIT(fan)))
|
||||
return 0;
|
||||
if (nr == 5 && data->kind != nct6775)
|
||||
|
@ -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 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
|
||||
|
@ -2371,9 +2418,9 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
|
|||
if (val > 1)
|
||||
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 (val)
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
return count;
|
||||
}
|
||||
|
@ -2382,7 +2429,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
|
|||
data->pwm_mode[nr] = val;
|
||||
reg = nct6775_read_value(data, data->REG_PWM_MODE[nr]);
|
||||
reg &= ~data->PWM_MODE_MASK[nr];
|
||||
if (val)
|
||||
if (!val)
|
||||
reg |= data->PWM_MODE_MASK[nr];
|
||||
nct6775_write_value(data, data->REG_PWM_MODE[nr], reg);
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
@ -3004,6 +3051,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
|
|||
case nct6792:
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
|
||||
val);
|
||||
reg = nct6775_read_value(data,
|
||||
|
@ -3358,8 +3406,10 @@ static inline void nct6775_init_device(struct nct6775_data *data)
|
|||
static void
|
||||
nct6775_check_fan_inputs(struct nct6775_data *data)
|
||||
{
|
||||
bool fan3pin, fan4pin, fan4min, fan5pin, fan6pin;
|
||||
bool pwm3pin, pwm4pin, pwm5pin, pwm6pin;
|
||||
bool fan3pin = false, fan4pin = false, fan4min = false;
|
||||
bool fan5pin = false, fan6pin = false, fan7pin = false;
|
||||
bool pwm3pin = false, pwm4pin = false, pwm5pin = false;
|
||||
bool pwm6pin = false, pwm7pin = false;
|
||||
int sioreg = data->sioreg;
|
||||
int regval;
|
||||
|
||||
|
@ -3376,12 +3426,6 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
|
|||
|
||||
/* On NCT6775, fan4 shares pins with the fdc interface */
|
||||
fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
|
||||
fan4min = false;
|
||||
fan5pin = false;
|
||||
fan6pin = false;
|
||||
pwm4pin = false;
|
||||
pwm5pin = false;
|
||||
pwm6pin = false;
|
||||
} else if (data->kind == nct6776) {
|
||||
bool gpok = superio_inb(sioreg, 0x27) & 0x80;
|
||||
const char *board_vendor, *board_name;
|
||||
|
@ -3421,25 +3465,15 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
|
|||
fan5pin = superio_inb(sioreg, 0x1C) & 0x02;
|
||||
|
||||
fan4min = fan4pin;
|
||||
fan6pin = false;
|
||||
pwm3pin = fan3pin;
|
||||
pwm4pin = false;
|
||||
pwm5pin = false;
|
||||
pwm6pin = false;
|
||||
} else if (data->kind == nct6106) {
|
||||
regval = superio_inb(sioreg, 0x24);
|
||||
fan3pin = !(regval & 0x80);
|
||||
pwm3pin = regval & 0x08;
|
||||
|
||||
fan4pin = false;
|
||||
fan4min = false;
|
||||
fan5pin = false;
|
||||
fan6pin = false;
|
||||
pwm4pin = false;
|
||||
pwm5pin = false;
|
||||
pwm6pin = false;
|
||||
} else { /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, or NCT6795D */
|
||||
int regval_1b, regval_2a, regval_eb;
|
||||
} else {
|
||||
/* NCT6779D, NCT6791D, NCT6792D, NCT6793D, NCT6795D, NCT6796D */
|
||||
int regval_1b, regval_2a, regval_2f;
|
||||
bool dsw_en;
|
||||
|
||||
regval = superio_inb(sioreg, 0x1c);
|
||||
|
||||
|
@ -3460,31 +3494,60 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
|
|||
break;
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
regval_1b = superio_inb(sioreg, 0x1b);
|
||||
regval_2a = superio_inb(sioreg, 0x2a);
|
||||
regval_2f = superio_inb(sioreg, 0x2f);
|
||||
dsw_en = regval_2f & BIT(3);
|
||||
|
||||
if (!pwm5pin)
|
||||
pwm5pin = regval & BIT(7);
|
||||
fan6pin = regval & BIT(1);
|
||||
pwm6pin = regval & BIT(0);
|
||||
|
||||
if (!fan5pin)
|
||||
fan5pin = regval_1b & BIT(5);
|
||||
|
||||
superio_select(sioreg, NCT6775_LD_12);
|
||||
regval_eb = superio_inb(sioreg, 0xeb);
|
||||
if (!fan5pin)
|
||||
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 != nct6796) {
|
||||
int regval_eb = superio_inb(sioreg, 0xeb);
|
||||
|
||||
if (!dsw_en) {
|
||||
fan6pin = regval & BIT(1);
|
||||
pwm6pin = regval & BIT(0);
|
||||
}
|
||||
|
||||
if (!fan5pin)
|
||||
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;
|
||||
default: /* NCT6779D */
|
||||
fan6pin = false;
|
||||
pwm6pin = false;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3493,11 +3556,11 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
|
|||
|
||||
/* fan 1 and 2 (0x03) are always present */
|
||||
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) |
|
||||
(fan5pin << 4);
|
||||
(fan5pin << 4) | (fan6pin << 5) | (fan7pin << 6);
|
||||
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,
|
||||
|
@ -3856,8 +3919,9 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
case nct6792:
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
data->in_num = 15;
|
||||
data->pwm_num = 6;
|
||||
data->pwm_num = (data->kind == nct6796) ? 7 : 6;
|
||||
data->auto_pwm_num = 4;
|
||||
data->has_fan_div = false;
|
||||
data->temp_fixed_num = 6;
|
||||
|
@ -3891,6 +3955,10 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
data->temp_label = nct6795_temp_label;
|
||||
data->temp_mask = NCT6795_TEMP_MASK;
|
||||
break;
|
||||
case nct6796:
|
||||
data->temp_label = nct6796_temp_label;
|
||||
data->temp_mask = NCT6796_TEMP_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
data->REG_CONFIG = NCT6775_REG_CONFIG;
|
||||
|
@ -4159,6 +4227,7 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
case nct6792:
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4193,6 +4262,7 @@ static int nct6775_probe(struct platform_device *pdev)
|
|||
case nct6792:
|
||||
case nct6793:
|
||||
case nct6795:
|
||||
case nct6796:
|
||||
tmp |= 0x7e;
|
||||
break;
|
||||
}
|
||||
|
@ -4291,7 +4361,8 @@ static int __maybe_unused nct6775_resume(struct device *dev)
|
|||
superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
|
||||
|
||||
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);
|
||||
|
||||
superio_exit(sioreg);
|
||||
|
@ -4391,6 +4462,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
|
|||
case SIO_NCT6795_ID:
|
||||
sio_data->kind = nct6795;
|
||||
break;
|
||||
case SIO_NCT6796_ID:
|
||||
sio_data->kind = nct6796;
|
||||
break;
|
||||
default:
|
||||
if (val != 0xffff)
|
||||
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)
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
superio_exit(sioaddr);
|
||||
|
|
|
@ -31,8 +31,8 @@ config SENSORS_ADM1275
|
|||
default n
|
||||
help
|
||||
If you say yes here you get hardware monitoring support for Analog
|
||||
Devices ADM1075, ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294
|
||||
Hot-Swap Controller and Digital Power Monitors.
|
||||
Devices ADM1075, ADM1272, ADM1275, ADM1276, ADM1278, ADM1293,
|
||||
and ADM1294 Hot-Swap Controller and Digital Power Monitors.
|
||||
|
||||
This driver can also be built as a module. If so, the module will
|
||||
be called adm1275.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* and Digital Power Monitor
|
||||
*
|
||||
* Copyright (c) 2011 Ericsson AB.
|
||||
* Copyright (c) 2018 Guenter Roeck
|
||||
*
|
||||
* 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
|
||||
|
@ -24,7 +25,7 @@
|
|||
#include <linux/bitops.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 ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5)
|
||||
|
@ -41,6 +42,8 @@ enum chips { adm1075, adm1275, adm1276, adm1278, adm1293, adm1294 };
|
|||
#define ADM1075_IRANGE_25 BIT(3)
|
||||
#define ADM1075_IRANGE_MASK (BIT(3) | BIT(4))
|
||||
|
||||
#define ADM1272_IRANGE BIT(0)
|
||||
|
||||
#define ADM1278_TEMP1_EN BIT(3)
|
||||
#define ADM1278_VIN_EN BIT(2)
|
||||
#define ADM1278_VOUT_EN BIT(1)
|
||||
|
@ -105,6 +108,19 @@ static const struct coefficients adm1075_coefficients[] = {
|
|||
[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[] = {
|
||||
[0] = { 19199, 0, -2 }, /* voltage, vrange 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)
|
|||
const struct adm1275_data *data = to_adm1275_data(info);
|
||||
int ret = 0;
|
||||
|
||||
if (page)
|
||||
if (page > 0)
|
||||
return -ENXIO;
|
||||
|
||||
switch (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);
|
||||
int ret;
|
||||
|
||||
if (page)
|
||||
if (page > 0)
|
||||
return -ENXIO;
|
||||
|
||||
switch (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[] = {
|
||||
{ "adm1075", adm1075 },
|
||||
{ "adm1272", adm1272 },
|
||||
{ "adm1275", adm1275 },
|
||||
{ "adm1276", adm1276 },
|
||||
{ "adm1278", adm1278 },
|
||||
|
@ -451,6 +468,54 @@ static int adm1275_probe(struct i2c_client *client,
|
|||
info->func[0] |=
|
||||
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
|
||||
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:
|
||||
if (device_config & ADM1275_IOUT_WARN2_SELECT)
|
||||
data->have_oc_fault = true;
|
||||
|
|
|
@ -45,7 +45,7 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (page)
|
||||
if (page > 0)
|
||||
return -ENXIO;
|
||||
|
||||
switch (reg) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
|
@ -27,6 +28,8 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/pmbus.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include "pmbus.h"
|
||||
|
||||
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_FAN_CONFIG_INDEX 0xe7
|
||||
#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
|
||||
|
||||
/* 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_PAGE(x) ((x) & 0x0f)
|
||||
|
||||
|
@ -47,12 +61,29 @@ enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
|
|||
|
||||
#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 {
|
||||
u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX];
|
||||
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)
|
||||
|
||||
struct ucd9000_debugfs_entry {
|
||||
struct i2c_client *client;
|
||||
u8 index;
|
||||
};
|
||||
|
||||
static int ucd9000_get_fan_config(struct i2c_client *client, int fan)
|
||||
{
|
||||
int fan_config = 0;
|
||||
|
@ -149,6 +180,312 @@ static const struct of_device_id 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,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -263,7 +600,18 @@ static int ucd9000_probe(struct i2c_client *client,
|
|||
| 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 */
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Data sheet available (5/2010) at
|
||||
* http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf
|
||||
* Data sheet available at http://www.sensirion.com/file/datasheet_sht21
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -136,20 +136,24 @@ static int via_cputemp_probe(struct platform_device *pdev)
|
|||
data->id = pdev->id;
|
||||
data->name = "via_cputemp";
|
||||
|
||||
switch (c->x86_model) {
|
||||
case 0xA:
|
||||
/* C7 A */
|
||||
case 0xD:
|
||||
/* C7 D */
|
||||
data->msr_temp = 0x1169;
|
||||
data->msr_vid = 0x198;
|
||||
break;
|
||||
case 0xF:
|
||||
/* Nano */
|
||||
if (c->x86 == 7) {
|
||||
data->msr_temp = 0x1423;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
} else {
|
||||
switch (c->x86_model) {
|
||||
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 */
|
||||
|
@ -283,6 +287,7 @@ static const struct x86_cpu_id __initconst cputemp_ids[] = {
|
|||
{ X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */
|
||||
{ X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */
|
||||
{ X86_VENDOR_CENTAUR, 6, 0xf, }, /* Nano */
|
||||
{ X86_VENDOR_CENTAUR, 7, X86_MODEL_ANY, },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, cputemp_ids);
|
||||
|
|
Loading…
Reference in New Issue