diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-09 19:59:54 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-09 19:59:54 -0700 |
commit | 71219b3494a32b5e1f22c4b1a5be2eb0d5524057 (patch) | |
tree | 682f2079dd82f5b929aa550e96a2fd417e135419 | |
parent | c18bb396d3d261ebbb4efbc05129c5d354c541e4 (diff) | |
parent | e3a2d2be510ec8a35ecd2a17a42467d417962bb7 (diff) |
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
-rw-r--r-- | Documentation/hwmon/adm1275 | 20 | ||||
-rw-r--r-- | Documentation/hwmon/lm92 | 6 | ||||
-rw-r--r-- | Documentation/hwmon/nct6775 | 56 | ||||
-rw-r--r-- | Documentation/hwmon/sht21 | 6 | ||||
-rw-r--r-- | Documentation/hwmon/sht3x | 2 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 5 | ||||
-rw-r--r-- | drivers/hwmon/g762.c | 53 | ||||
-rw-r--r-- | drivers/hwmon/lm92.c | 63 | ||||
-rw-r--r-- | drivers/hwmon/nct6775.c | 231 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/Kconfig | 4 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/adm1275.c | 71 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max8688.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/ucd9000.c | 350 | ||||
-rw-r--r-- | drivers/hwmon/sht21.c | 3 | ||||
-rw-r--r-- | drivers/hwmon/via-cputemp.c | 31 |
15 files changed, 662 insertions, 241 deletions
diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275 index 791bc0bd91e6..39033538eb03 100644 --- a/Documentation/hwmon/adm1275 +++ b/Documentation/hwmon/adm1275 @@ -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. diff --git a/Documentation/hwmon/lm92 b/Documentation/hwmon/lm92 index 22f68ad032cf..cfa99a353b8c 100644 --- a/Documentation/hwmon/lm92 +++ b/Documentation/hwmon/lm92 @@ -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: diff --git a/Documentation/hwmon/nct6775 b/Documentation/hwmon/nct6775 index 76add4c9cd68..bd59834d310f 100644 --- a/Documentation/hwmon/nct6775 +++ b/Documentation/hwmon/nct6775 @@ -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 ----------- diff --git a/Documentation/hwmon/sht21 b/Documentation/hwmon/sht21 index 47f4765db256..8b3cdda541c1 100644 --- a/Documentation/hwmon/sht21 +++ b/Documentation/hwmon/sht21 @@ -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> diff --git a/Documentation/hwmon/sht3x b/Documentation/hwmon/sht3x index b0d88184f48e..d9daa6ab1e8e 100644 --- a/Documentation/hwmon/sht3x +++ b/Documentation/hwmon/sht3x @@ -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> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 033e57366d56..f249a4428458 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -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. diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index 6d1208b2b6d2..6c83c385a7ca 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -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, }; diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 2a91974a10bb..d40fe5122e94 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -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); diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index c219e43b8f02..aebce560bfaf 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -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); diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index 6e4298e99222..e71aec69e76e 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -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. diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 00d6995af4c2..13600fa79e7f 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -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; diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index dd4883a19045..e951f9b87abb 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c @@ -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) { diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index b74dbeca2e8d..70cecb06f93c 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -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 */ diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index 190e7b39ce32..2c7ba70921f5 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -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> diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index 07a0cb0a1f28..0e81f287d305 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -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); |