Commit 177808cd authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-linus-3.19' of...

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

Pull hwmon updates from Guenter Roeck:
 "Notable changes:
   - new driver for NCT7802Y
   - support for TMP435, LM95233, LM95235, NCT6792D, and NXP LM75B
   - regulator support for PMBus chips, specifically LTX2978
   - support for humidity sensors to iio-hwmon bridge driver

* tag 'hwmon-for-linus-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (21 commits)
  hwmon: (tmp401) Detect TMP435 on all addresses it supports
  hwmon: (lm75) Strengthen detect function
  hwmon: (gpio-fan) Add a shutdown handler to poweroff the fans
  hwmon: (gpio-fan) Allow usage of gpio operations that may sleep
  hwmon: (tmp401) Bail out from tmp401_probe() in case of write errors
  hwmon: (tmp401) Add support for TI TMP435
  hwmon: (lm95234) Add support for LM95233
  hwmon: (lm95245) Add support for LM95235
  hwmon: (ina2xx) bail-out from ina2xx_probe() in case of configuration errors
  hwmon: (nct6775) Add blank lines after declarations
  hwmon: (nct6775) Add support for NCT6792D
  hwmon: (nct6775) Documentation updates
  hwmon: (lm75) Add support for the NXP LM75B
  hwmon: Driver for Nuvoton NCT7802Y
  hwmon: (ibmpowernv) Convert to module_platform_driver
  hwmon: (ibmpowernv) Use platform 'id_table' to probe the device
  hwmon: (iio_hwmon) Add support for humidity sensors
  hwmon: (ltc2978) Add regulator support
  hwmon: (pmbus) Add regulator support
  hwmon: (pmbus) add helpers for byte write and read modify write
  ...
parents 0160928e 907a6d58
ltc2978
Required properties:
- compatible: should contain one of:
* "lltc,ltc2974"
* "lltc,ltc2977"
* "lltc,ltc2978"
* "lltc,ltc3880"
* "lltc,ltc3883"
* "lltc,ltm4676"
- reg: I2C slave address
Optional properties:
- regulators: A node that houses a sub-node for each regulator controlled by
the device. Each sub-node is identified using the node's name, with valid
values listed below. The content of each sub-node is defined by the
standard binding for regulators; see regulator.txt.
Valid names of regulators depend on number of supplies supported per device:
* ltc2974 : vout0 - vout3
* ltc2977 : vout0 - vout7
* ltc2978 : vout0 - vout7
* ltc3880 : vout0 - vout1
* ltc3883 : vout0
* ltm4676 : vout0 - vout1
Example:
ltc2978@5e {
compatible = "lltc,ltc2978";
reg = <0x5e>;
regulators {
vout0 {
regulator-name = "FPGA-2.5V";
};
vout2 {
regulator-name = "FPGA-1.5V";
};
};
};
......@@ -53,6 +53,11 @@ Supported chips:
http://www.ti.com/product/tmp75
http://www.ti.com/product/tmp175
http://www.ti.com/product/tmp275
* NXP LM75B
Prefix: 'lm75b'
Addresses scanned: none
Datasheet: Publicly available at the NXP website
http://www.nxp.com/documents/data_sheet/LM75B.pdf
Author: Frodo Looijaard <frodol@dds.nl>
......
......@@ -2,6 +2,10 @@ Kernel driver lm95234
=====================
Supported chips:
* National Semiconductor / Texas Instruments LM95233
Addresses scanned: I2C 0x18, 0x2a, 0x2b
Datasheet: Publicly available at the Texas Instruments website
http://www.ti.com/product/lm95233
* National Semiconductor / Texas Instruments LM95234
Addresses scanned: I2C 0x18, 0x4d, 0x4e
Datasheet: Publicly available at the Texas Instruments website
......@@ -13,11 +17,12 @@ Author: Guenter Roeck <linux@roeck-us.net>
Description
-----------
LM95234 is an 11-bit digital temperature sensor with a 2-wire System Management
Bus (SMBus) interface and TrueTherm technology that can very accurately monitor
the temperature of four remote diodes as well as its own temperature.
The four remote diodes can be external devices such as microprocessors,
graphics processors or diode-connected 2N3904s. The LM95234's TruTherm
LM95233 and LM95234 are 11-bit digital temperature sensors with a 2-wire
System Management Bus (SMBus) interface and TrueTherm technology
that can very accurately monitor the temperature of two (LM95233)
or four (LM95234) remote diodes as well as its own temperature.
The remote diodes can be external devices such as microprocessors,
graphics processors or diode-connected 2N3904s. The chip's TruTherm
beta compensation technology allows sensing of 90 nm or 65 nm process
thermal diodes accurately.
......
......@@ -2,10 +2,14 @@ Kernel driver lm95245
==================
Supported chips:
* National Semiconductor LM95245
* TI LM95235
Addresses scanned: I2C 0x18, 0x29, 0x4c
Datasheet: Publicly available at the TI website
http://www.ti.com/lit/ds/symlink/lm95235.pdf
* TI / National Semiconductor LM95245
Addresses scanned: I2C 0x18, 0x19, 0x29, 0x4c, 0x4d
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/mpf/LM/LM95245.html
Datasheet: Publicly available at the TI website
http://www.ti.com/lit/ds/symlink/lm95245.pdf
Author: Alexander Stein <alexander.stein@systec-electronic.com>
......@@ -13,10 +17,10 @@ Author: Alexander Stein <alexander.stein@systec-electronic.com>
Description
-----------
The LM95245 is an 11-bit digital temperature sensor with a 2-wire System
LM95235 and LM95245 are 11-bit digital temperature sensors with a 2-wire System
Management Bus (SMBus) interface and TruTherm technology that can monitor
the temperature of a remote diode as well as its own temperature.
The LM95245 can be used to very accurately monitor the temperature of
The chips can be used to very accurately monitor the temperature of
external devices such as microprocessors.
All temperature values are given in millidegrees Celsius. Local temperature
......
......@@ -8,11 +8,15 @@ Kernel driver NCT6775
=====================
Supported chips:
* Nuvoton NCT6102D/NCT6104D/NCT6106D
Prefix: 'nct6106'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from the Nuvoton web site
* Nuvoton NCT5572D/NCT6771F/NCT6772F/NCT6775F/W83677HG-I
Prefix: 'nct6775'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
* Nuvoton NCT5577D/NCT6776D/NCT6776F
* Nuvoton NCT5573D/NCT5577D/NCT6776D/NCT6776F
Prefix: 'nct6776'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
......@@ -20,6 +24,14 @@ Supported chips:
Prefix: 'nct6779'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
* Nuvoton NCT6791D
Prefix: 'nct6791'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
* Nuvoton NCT6792D
Prefix: 'nct6792'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
Authors:
Guenter Roeck <linux@roeck-us.net>
......
Kernel driver nct7802
=====================
Supported chips:
* Nuvoton NCT7802Y
Prefix: 'nct7802'
Addresses scanned: I2C 0x28..0x2f
Datasheet: Available from Nuvoton web site
Authors:
Guenter Roeck <linux@roeck-us.net>
Description
-----------
This driver implements support for the Nuvoton NCT7802Y hardware monitoring
chip. NCT7802Y supports 6 temperature sensors, 5 voltage sensors, and 3 fan
speed sensors.
The chip also supports intelligent fan speed control. This functionality is
not currently supported by the driver.
Tested Boards and BIOS Versions
-------------------------------
The driver has been reported to work with the following boards and
BIOS versions.
Board BIOS version
---------------------------------------------------------------
Kontron COMe-bSC2 CHR2E934.001.GGO
Kontron COMe-bIP2 CCR2E212
......@@ -18,6 +18,10 @@ Supported chips:
Prefix: 'tmp432'
Addresses scanned: I2C 0x4c, 0x4d
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp432.html
* Texas Instruments TMP435
Prefix: 'tmp435'
Addresses scanned: I2C 0x37, 0x48 - 0x4f
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp435.html
Authors:
Hans de Goede <hdegoede@redhat.com>
......@@ -27,8 +31,8 @@ Description
-----------
This driver implements support for Texas Instruments TMP401, TMP411,
TMP431, and TMP432 chips. These chips implement one or two remote and
one local temperature sensors. Temperature is measured in degrees
TMP431, TMP432 and TMP435 chips. These chips implement one or two remote
and one local temperature sensors. Temperature is measured in degrees
Celsius. Resolution of the remote sensor is 0.0625 degree. Local
sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not
supported by the driver so far, so using the default resolution of 0.5
......
......@@ -20,7 +20,9 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/of_platform.h>
#include <asm/opal.h>
#include <asm/machdep.h>
static DEFINE_MUTEX(opal_sensor_mutex);
......@@ -64,3 +66,21 @@ int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data)
return ret;
}
EXPORT_SYMBOL_GPL(opal_get_sensor_data);
static __init int opal_sensor_init(void)
{
struct platform_device *pdev;
struct device_node *sensor;
sensor = of_find_node_by_path("/ibm,opal/sensors");
if (!sensor) {
pr_err("Opal node 'sensors' not found\n");
return -ENODEV;
}
pdev = of_platform_device_create(sensor, "opal-sensor", NULL);
of_node_put(sensor);
return PTR_ERR_OR_ZERO(pdev);
}
machine_subsys_initcall(powernv, opal_sensor_init);
......@@ -1028,11 +1028,11 @@ config SENSORS_LM93
will be called lm93.
config SENSORS_LM95234
tristate "National Semiconductor LM95234"
tristate "National Semiconductor LM95234 and compatibles"
depends on I2C
help
If you say yes here you get support for the LM95234 temperature
sensor.
If you say yes here you get support for the LM95233 and LM95234
temperature sensor chips.
This driver can also be built as a module. If so, the module
will be called lm95234.
......@@ -1048,10 +1048,11 @@ config SENSORS_LM95241
will be called lm95241.
config SENSORS_LM95245
tristate "National Semiconductor LM95245 sensor chip"
tristate "National Semiconductor LM95245 and compatibles"
depends on I2C
help
If you say yes here you get support for LM95245 sensor chip.
If you say yes here you get support for LM95235 and LM95245
temperature sensor chips.
This driver can also be built as a module. If so, the module
will be called lm95245.
......@@ -1117,12 +1118,23 @@ 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 and compatible Super-I/O chips. This driver replaces the
w83627ehf driver for NCT6775F and NCT6776F.
NCT6791D, NCT6792D 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.
config SENSORS_NCT7802
tristate "Nuvoton NCT7802Y"
depends on I2C
select REGMAP_I2C
help
If you say yes here you get support for the Nuvoton NCT7802Y
hardware monitoring chip.
This driver can also be built as a module. If so, the module
will be called nct7802.
config SENSORS_PCF8591
tristate "Philips PCF8591 ADC/DAC"
depends on I2C
......@@ -1454,7 +1466,7 @@ config SENSORS_TMP401
depends on I2C
help
If you say yes here you get support for Texas Instruments TMP401,
TMP411, TMP431, and TMP432 temperature sensor chips.
TMP411, TMP431, TMP432 and TMP435 temperature sensor chips.
This driver can also be built as a module. If so, the module
will be called tmp401.
......
......@@ -118,6 +118,7 @@ obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o
obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o
obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o
obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
......
......@@ -79,7 +79,7 @@ static ssize_t show_fan_alarm(struct device *dev,
{
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
struct gpio_fan_alarm *alarm = fan_data->alarm;
int value = gpio_get_value(alarm->gpio);
int value = gpio_get_value_cansleep(alarm->gpio);
if (alarm->active_low)
value = !value;
......@@ -131,7 +131,7 @@ static void __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val)
int i;
for (i = 0; i < fan_data->num_ctrl; i++)
gpio_set_value(fan_data->ctrl[i], (ctrl_val >> i) & 1);
gpio_set_value_cansleep(fan_data->ctrl[i], (ctrl_val >> i) & 1);
}
static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
......@@ -142,7 +142,7 @@ static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
for (i = 0; i < fan_data->num_ctrl; i++) {
int value;
value = gpio_get_value(fan_data->ctrl[i]);
value = gpio_get_value_cansleep(fan_data->ctrl[i]);
ctrl_val |= (value << i);
}
return ctrl_val;
......@@ -369,7 +369,8 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
if (err)
return err;
err = gpio_direction_output(ctrl[i], gpio_get_value(ctrl[i]));
err = gpio_direction_output(ctrl[i],
gpio_get_value_cansleep(ctrl[i]));
if (err)
return err;
}
......@@ -549,6 +550,14 @@ static int gpio_fan_probe(struct platform_device *pdev)
return 0;
}
static void gpio_fan_shutdown(struct platform_device *pdev)
{
struct gpio_fan_data *fan_data = dev_get_drvdata(&pdev->dev);
if (fan_data->ctrl)
set_fan_speed(fan_data, 0);
}
#ifdef CONFIG_PM_SLEEP
static int gpio_fan_suspend(struct device *dev)
{
......@@ -580,6 +589,7 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
static struct platform_driver gpio_fan_driver = {
.probe = gpio_fan_probe,
.shutdown = gpio_fan_shutdown,
.driver = {
.name = "gpio-fan",
.pm = GPIO_FAN_PM,
......
......@@ -74,9 +74,6 @@ struct platform_data {
u32 sensors_count; /* Total count of sensors from each group */
};
/* Platform device representing all the ibmpowernv sensors */
static struct platform_device *pdevice;
static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr,
char *buf)
{
......@@ -99,7 +96,7 @@ static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr,
return sprintf(buf, "%u\n", x);
}
static int __init get_sensor_index_attr(const char *name, u32 *index,
static int get_sensor_index_attr(const char *name, u32 *index,
char *attr)
{
char *hash_pos = strchr(name, '#');
......@@ -136,7 +133,7 @@ static int __init get_sensor_index_attr(const char *name, u32 *index,
* which need to be mapped as fan2_input, temp1_max respectively before
* populating them inside hwmon device class.
*/
static int __init create_hwmon_attr_name(struct device *dev, enum sensors type,
static int create_hwmon_attr_name(struct device *dev, enum sensors type,
const char *node_name,
char *hwmon_attr_name)
{
......@@ -172,7 +169,7 @@ static int __init create_hwmon_attr_name(struct device *dev, enum sensors type,
return 0;
}
static int __init populate_attr_groups(struct platform_device *pdev)
static int populate_attr_groups(struct platform_device *pdev)
{
struct platform_data *pdata = platform_get_drvdata(pdev);
const struct attribute_group **pgroups = pdata->attr_groups;
......@@ -180,11 +177,6 @@ static int __init populate_attr_groups(struct platform_device *pdev)
enum sensors type;
opal = of_find_node_by_path("/ibm,opal/sensors");
if (!opal) {
dev_dbg(&pdev->dev, "Opal node 'sensors' not found\n");
return -ENODEV;
}
for_each_child_of_node(opal, np) {
if (np->name == NULL)
continue;
......@@ -221,7 +213,7 @@ static int __init populate_attr_groups(struct platform_device *pdev)
* to the name required by the higher 'hwmon' driver like fan1_input, temp1_max
* etc..
*/
static int __init create_device_attrs(struct platform_device *pdev)
static int create_device_attrs(struct platform_device *pdev)
{
struct platform_data *pdata = platform_get_drvdata(pdev);
const struct attribute_group **pgroups = pdata->attr_groups;
......@@ -280,7 +272,7 @@ static int __init create_device_attrs(struct platform_device *pdev)
return err;
}
static int __init ibmpowernv_probe(struct platform_device *pdev)
static int ibmpowernv_probe(struct platform_device *pdev)
{
struct platform_data *pdata;
struct device *hwmon_dev;
......@@ -309,57 +301,25 @@ static int __init ibmpowernv_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static struct platform_driver ibmpowernv_driver = {
.driver = {
.owner = THIS_MODULE,
.name = DRVNAME,
static const struct platform_device_id opal_sensor_driver_ids[] = {
{
.name = "opal-sensor",
},
{ }
};
MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids);
static int __init ibmpowernv_init(void)
{
int err;
pdevice = platform_device_alloc(DRVNAME, 0);
if (!pdevice) {
pr_err("Device allocation failed\n");
err = -ENOMEM;
goto exit;
}
err = platform_device_add(pdevice);
if (err) {
pr_err("Device addition failed (%d)\n", err);
goto exit_device_put;
}
err = platform_driver_probe(&ibmpowernv_driver, ibmpowernv_probe);
if (err) {
if (err != -ENODEV)
pr_err("Platform driver probe failed (%d)\n", err);
goto exit_device_del;
}
return 0;
exit_device_del:
platform_device_del(pdevice);
exit_device_put:
platform_device_put(pdevice);
exit:
return err;
}
static struct platform_driver ibmpowernv_driver = {
.probe = ibmpowernv_probe,
.id_table = opal_sensor_driver_ids,
.driver = {
.owner = THIS_MODULE,
.name = DRVNAME,
},
};
static void __exit ibmpowernv_exit(void)
{
platform_driver_unregister(&ibmpowernv_driver);
platform_device_unregister(pdevice);
}
module_platform_driver(ibmpowernv_driver);
MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
MODULE_DESCRIPTION("IBM POWERNV platform sensors");
MODULE_LICENSE("GPL");
module_init(ibmpowernv_init);
module_exit(ibmpowernv_exit);
......@@ -63,7 +63,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
struct iio_hwmon_state *st;
struct sensor_device_attribute *a;
int ret, i;
int in_i = 1, temp_i = 1, curr_i = 1;
int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1;
enum iio_chan_type type;
struct iio_channel *channels;
const char *name = "iio_hwmon";
......@@ -123,6 +123,11 @@ static int iio_hwmon_probe(struct platform_device *pdev)
"curr%d_input",
curr_i++);
break;
case IIO_HUMIDITYRELATIVE:
a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
"humidity%d_input",
humidity_i++);
break;
default:
ret = -EINVAL;
goto error_release_channels;
......
......@@ -223,6 +223,7 @@ static int ina2xx_probe(struct i2c_client *client,
struct device *hwmon_dev;
long shunt = 10000; /* default shunt value 10mOhms */
u32 val;
int ret;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
......@@ -247,12 +248,25 @@ static int ina2xx_probe(struct i2c_client *client,
data->config = &ina2xx_config[data->kind];
/* device configuration */
i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
data->config->config_default);
/* set current LSB to 1mA, shunt is in uOhms */
/* (equation 13 in datasheet) */
i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
data->config->calibration_factor / shunt);
ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
data->config->config_default);
if (ret < 0) {
dev_err(dev,
"error writing to the config register: %d", ret);
return -ENODEV;
}
/*
* Set current LSB to 1mA, shunt is in uOhms
* (equation 13 in datasheet).
*/
ret = i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
data->config->calibration_factor / shunt);
if (ret < 0) {
dev_err(dev,
"error writing to the calibration register: %d", ret);
return -ENODEV;
}
data->client = client;
mutex_init(&data->update_lock);
......
......@@ -44,6 +44,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
g751,
lm75,
lm75a,
lm75b,
max6625,
max6626,
mcp980x,
......@@ -233,6 +234,10 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
data->resolution = 9;
data->sample_time = HZ / 2;
break;
case lm75b:
data->resolution = 11;
data->sample_time = HZ / 4;
break;
case max6625:
data->resolution = 9;
data->sample_time = HZ / 4;
......@@ -322,6 +327,7 @@ static const struct i2c_device_id lm75_ids[] = {
{ "g751", g751, },
{ "lm75", lm75, },
{ "lm75a", lm75a, },
{ "lm75b", lm75b, },
{ "max6625", max6625, },
{ "max6626", max6626, },
{ "mcp980x", mcp980x, },
......@@ -409,6 +415,12 @@ static int lm75_detect(struct i2c_client *new_client,
|| i2c_smbus_read_byte_data(new_client, 7) != os)
return -ENODEV;
}
/*
* It is very unlikely that this is a LM75 if both
* hysteresis and temperature limit registers are 0.
*/
if (hyst == 0 && os == 0)
return -ENODEV;
/* Addresses cycling */
for (i = 8; i <= 248; i += 40) {
......
/*
* Driver for Texas Instruments / National Semiconductor LM95234
*
* Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
* Copyright (c) 2013, 2014 Guenter Roeck <linux@roeck-us.net>
*
* Derived from lm95241.c
* Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
......@@ -30,7 +30,10 @@
#define DRVNAME "lm95234"
static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END };
enum chips { lm95233, lm95234 };
static const unsigned short normal_i2c[] = {
0x18, 0x2a, 0x2b, 0x4d, 0x4e, I2C_CLIENT_END };
/* LM95234 registers */
#define LM95234_REG_MAN_ID 0xFE
......@@ -53,11 +56,13 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END };
#define LM95234_REG_TCRIT_HYST 0x5a
#define NATSEMI_MAN_ID 0x01
#define LM95233_CHIP_ID 0x89
#define LM95234_CHIP_ID 0x79
/* Client data (each client gets its own) */
struct lm95234_data {
struct i2c_client *client;
const struct attribute_group *groups[3];
struct mutex update_lock;
unsigned long last_updated, interval; /* in jiffies */
bool valid; /* false until following fields are valid */
......@@ -564,35 +569,23 @@ static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset,
static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
set_interval);
static struct attribute *lm95234_attrs[] = {
static struct attribute *lm95234_common_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp4_input.dev_attr.attr,
&sensor_dev_attr_temp5_input.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp4_fault.dev_attr.attr,
&sensor_dev_attr_temp5_fault.dev_attr.attr,
&sensor_dev_attr_temp2_type.dev_attr.attr,
&sensor_dev_attr_temp3_type.dev_attr.attr,
&sensor_dev_attr_temp4_type.dev_attr.attr,
&sensor_dev_attr_temp5_type.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp4_max.dev_attr.attr,
&sensor_dev_attr_temp5_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
&sensor_dev_attr_temp3_crit.dev_attr.attr,
&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
......@@ -601,18 +594,44 @@ static struct attribute *lm95234_attrs[] = {
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp3_offset.dev_attr.attr,
&dev_attr_update_interval.attr,
NULL
};
static const struct attribute_group lm95234_common_group = {
.attrs = lm95234_common_attrs,
};
static struct attribute *lm95234_attrs[] = {
&sensor_dev_attr_temp4_input.dev_attr.attr,
&sensor_dev_attr_temp5_input.dev_attr.attr,
&sensor_dev_attr_temp4_fault.dev_attr.attr,
&sensor_dev_attr_temp5_fault.dev_attr.attr,
&sensor_dev_attr_temp4_type.dev_attr.attr,
&sensor_dev_attr_temp5_type.dev_attr.attr,
&sensor_dev_attr_temp4_max.dev_attr.attr,
&sensor_dev_attr_temp5_max.dev_attr.attr,
&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_offset.dev_attr.attr,
&sensor_dev_attr_temp5_offset.dev_attr.attr,
&dev_attr_update_interval.attr,
NULL
};
ATTRIBUTE_GROUPS(lm95234);
static const struct attribute_group lm95234_group = {
.attrs = lm95234_attrs,
};
static int lm95234_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
int address = client->addr;
u8 config_mask, model_mask;
int mfg_id, chip_id, val;
const char *name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
......@@ -622,15 +641,31 @@ static int lm95234_detect(struct i2c_client *client,
return -ENODEV;
chip_id = i2c_smbus_read_byte_data(client, LM95234_REG_CHIP_ID);
if (chip_id != LM95234_CHIP_ID)
switch (chip_id) {
case LM95233_CHIP_ID:
if (address != 0x18 && address != 0x2a && address != 0x2b)
return -ENODEV;
config_mask = 0xbf;
model_mask = 0xf9;
name = "lm95233";
break;
case LM95234_CHIP_ID:
if (address != 0x18 && address != 0x4d && address != 0x4e)
return -ENODEV;
config_mask = 0xbc;
model_mask = 0xe1;
name = "lm95234";
break;
default:
return -ENODEV;
}
val = i2c_smbus_read_byte_data(client, LM95234_REG_STATUS);
if (val & 0x30)
return -ENODEV;
val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
if (val & 0xbc)
if (val & config_mask)
return -ENODEV;
val = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
......@@ -638,14 +673,14 @@ static int lm95234_detect(struct i2c_client *client,
return -ENODEV;
val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
if (val & 0xe1)
if (val & model_mask)
return -ENODEV;
val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
if (val & 0xe1)
if (val & model_mask)
return -ENODEV;
strlcpy(info->type, "lm95234", I2C_NAME_SIZE);
strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
}
......@@ -698,15 +733,19 @@ static int lm95234_probe(struct i2c_client *client,
if (err < 0)
return err;
data->groups[0] = &lm95234_common_group;
if (id->driver_data == lm95234)
data->groups[1] = &lm95234_group;
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
data,
lm95234_groups);
data, data->groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
/* Driver data (common to all clients) */
static const struct i2c_device_id lm95234_id[] = {
{ "lm95234", 0 },
{ "lm95233", lm95233 },
{ "lm95234", lm95234 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm95234_id);
......@@ -725,5 +764,5 @@ static struct i2c_driver lm95234_driver = {
module_i2c_driver(lm95234_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("LM95234 sensor driver");
MODULE_DESCRIPTION("LM95233/LM95234 sensor driver");
MODULE_LICENSE("GPL");
/*
* Copyright (C) 2011 Alexander Stein <alexander.stein@systec-electronic.com>
*
* The LM95245 is a sensor chip made by National Semiconductors.
* The LM95245 is a sensor chip made by TI / National Semiconductor.
* It reports up to two temperatures (its own plus an external one).
* Complete datasheet can be obtained from National's website at:
* http://www.national.com/ds.cgi/LM/LM95245.pdf
*
* This driver is based on lm95241.c
*
......@@ -34,8 +32,6 @@
#include <linux/mutex.h>
#include <linux/sysfs.h>
#define DEVNAME "lm95245"
static const unsigned short normal_i2c[] = {
0x18, 0x19, 0x29, 0x4c, 0x4d, I2C_CLIENT_END };
......@@ -98,7 +94,8 @@ static const unsigned short normal_i2c[] = {
#define STATUS1_LOC 0x01
#define MANUFACTURER_ID 0x01
#define DEFAULT_REVISION 0xB3
#define LM95235_REVISION 0xB1
#define LM95245_REVISION 0xB3
static const u8 lm95245_reg_address[] = {
LM95245_REG_R_LOCAL_TEMPH_S,
......@@ -427,17 +424,32 @@ static int lm95245_detect(struct i2c_client *new_client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = new_client->adapter;
int address = new_client->addr;
const char *name;
int rev, id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
if (i2c_smbus_read_byte_data(new_client, LM95245_REG_R_MAN_ID)
!= MANUFACTURER_ID
|| i2c_smbus_read_byte_data(new_client, LM95245_REG_R_CHIP_ID)
!= DEFAULT_REVISION)
id = i2c_smbus_read_byte_data(new_client, LM95245_REG_R_MAN_ID);
if (id != MANUFACTURER_ID)
return -ENODEV;
strlcpy(info->type, DEVNAME, I2C_NAME_SIZE);
rev = i2c_smbus_read_byte_data(new_client, LM95245_REG_R_CHIP_ID);
switch (rev) {
case LM95235_REVISION:
if (address != 0x18 && address != 0x29 && address != 0x4c)
return -ENODEV;
name = "lm95235";
break;
case LM95245_REVISION:
name = "lm95245";
break;
default:
return -ENODEV;
}
strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
}
......@@ -484,7 +496,8 @@ static int lm95245_probe(struct i2c_client *client,
/* Driver data (common to all clients) */
static const struct i2c_device_id lm95245_id[] = {
{ DEVNAME, 0 },
{ "lm95235", 0 },
{ "lm95245", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm95245_id);
......@@ -492,7 +505,7 @@ MODULE_DEVICE_TABLE(i2c, lm95245_id);
static struct i2c_driver lm95245_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = DEVNAME,
.name = "lm95245",
},
.probe = lm95245_probe,
.id_table = lm95245_id,
......@@ -503,5 +516,5 @@ static struct i2c_driver lm95245_driver = {
module_i2c_driver(lm95245_driver);
MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
MODULE_DESCRIPTION("LM95245 sensor driver");
MODULE_DESCRIPTION("LM95235/LM95245 sensor driver");
MODULE_LICENSE("GPL");
......@@ -38,6 +38,7 @@
* nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
* nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
* nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
* nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
*
* #temp lists the number of monitored temperature sources (first value) plus
* the number of directly connectable temperature sensors (second value).
......@@ -61,7 +62,7 @@
#define USE_ALTERNATE
enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791 };
enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792 };
/* used to set data->name = nct6775_device_names[data->sio_kind] */
static const char * const nct6775_device_names[] = {
......@@ -70,6 +71,7 @@ static const char * const nct6775_device_names[] = {
"nct6776",
"nct6779",
"nct6791",
"nct6792",
};
static unsigned short force_id;
......@@ -100,6 +102,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
#define SIO_NCT6776_ID 0xc330
#define SIO_NCT6779_ID 0xc560
#define SIO_NCT6791_ID 0xc800
#define SIO_NCT6792_ID 0xc910
#define SIO_ID_MASK 0xFFF0
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
......@@ -529,6 +532,12 @@ static const s8 NCT6791_ALARM_BITS[] = {
4, 5, 13, -1, -1, -1, /* temp1..temp6 */
12, 9 }; /* intrusion0, intrusion1 */
/* NCT6792 specific data */
static const u16 NCT6792_REG_TEMP_MON[] = {
0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
/* NCT6102D/NCT6106D specific data */
......@@ -1043,13 +1052,14 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
reg == 0x73 || reg == 0x75 || reg == 0x77;
case nct6779:
case nct6791:
case nct6792:
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 == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
reg == 0x7b;
reg == 0x7b || reg == 0x7d;
}
return false;
}
......@@ -1063,6 +1073,7 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
{
u8 bank = reg >> 8;
if (data->bank != bank) {
outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
outb_p(bank, data->addr + DATA_REG_OFFSET);
......@@ -1300,6 +1311,7 @@ static void nct6775_update_pwm(struct device *dev)
if (!data->target_speed_tolerance[i] ||
data->pwm_enable[i] == speed_cruise) {
u8 t = fanmodecfg & 0x0f;
if (data->REG_TOLERANCE_H) {
t |= (nct6775_read_value(data,
data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
......@@ -1391,6 +1403,7 @@ static void nct6775_update_pwm_limits(struct device *dev)
case nct6106:
case nct6779:
case nct6791:
case nct6792:
reg = nct6775_read_value(data,
data->REG_CRITICAL_PWM_ENABLE[i]);
if (reg & data->CRITICAL_PWM_ENABLE_MASK)
......@@ -1473,6 +1486,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
data->alarms = 0;
for (i = 0; i < NUM_REG_ALARM; i++) {
u8 alarm;
if (!data->REG_ALARM[i])
continue;
alarm = nct6775_read_value(data, data->REG_ALARM[i]);
......@@ -1482,6 +1496,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
data->beeps = 0;
for (i = 0; i < NUM_REG_BEEP; i++) {
u8 beep;
if (!data->REG_BEEP[i])
continue;
beep = nct6775_read_value(data, data->REG_BEEP[i]);
......@@ -1504,8 +1519,9 @@ show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int nr = sattr->nr;
int index = sattr->index;
int nr = sattr->nr;
return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
}
......@@ -1515,10 +1531,12 @@ store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
{
struct nct6775_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int nr = sattr->nr;
int index = sattr->index;
int nr = sattr->nr;
unsigned long val;
int err = kstrtoul(buf, 10, &val);
int err;
err = kstrtoul(buf, 10, &val);
if (err < 0)
return err;
mutex_lock(&data->update_lock);
......@@ -1535,6 +1553,7 @@ show_alarm(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);
int nr = data->ALARM_BITS[sattr->index];
return sprintf(buf, "%u\n",
(unsigned int)((data->alarms >> nr) & 0x01));
}
......@@ -1570,6 +1589,7 @@ show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
if (nr >= 0) {
int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
alarm = (data->alarms >> bit) & 0x01;
}
return sprintf(buf, "%u\n", alarm);
......@@ -1595,8 +1615,9 @@ store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
int nr = data->BEEP_BITS[sattr->index];
int regindex = nr >> 3;
unsigned long val;
int err;
int err = kstrtoul(buf, 10, &val);
err = kstrtoul(buf, 10, &val);
if (err < 0)
return err;
if (val > 1)
......@@ -1629,6 +1650,7 @@ show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
if (nr >= 0) {
int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
beep = (data->beeps >> bit) & 0x01;
}
return sprintf(buf, "%u\n", beep);
......@@ -1642,8 +1664,9 @@ store_temp_beep(struct device *dev, struct device_attribute *attr,
struct nct6775_data *data = dev_get_drvdata(dev);
int nr, bit, regindex;
unsigned long val;
int err;
int err = kstrtoul(buf, 10, &val);
err = kstrtoul(buf, 10, &val);
if (err < 0)
return err;
if (val > 1)
......@@ -1715,6 +1738,7 @@ show_fan(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);
int nr = sattr->index;
return sprintf(buf, "%d\n", data->rpm[nr]);
}
......@@ -1724,6 +1748,7 @@ show_fan_min(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);
int nr = sattr->index;
return sprintf(buf, "%d\n",
data->fan_from_reg_min(data->fan_min[nr],
data->fan_div[nr]));
......@@ -1735,6 +1760,7 @@ show_fan_div(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);
int nr = sattr->index;
return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
}
......@@ -1746,9 +1772,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int nr = sattr->index;
unsigned long val;
int err;
unsigned int reg;
u8 new_div;
int err;
err = kstrtoul(buf, 10, &val);
if (err < 0)
......@@ -1932,6 +1958,7 @@ show_temp_label(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);
int nr = sattr->index;
return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
}
......@@ -2008,6 +2035,7 @@ show_temp_type(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);
int nr = sattr->index;
return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
}
......@@ -2790,6 +2818,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
case nct6106:
case nct6779:
case nct6791:
case nct6792:
nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
val);
reg = nct6775_read_value(data,
......@@ -2997,6 +3026,7 @@ static ssize_t
show_vid(struct device *dev, struct device_attribute *attr, char *buf)
{
struct nct6775_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
}
......@@ -3202,7 +3232,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
pwm4pin = false;
pwm5pin = false;
pwm6pin = false;
} else { /* NCT6779D or NCT6791D */
} else { /* NCT6779D, NCT6791D, or NCT6792D */
regval = superio_inb(sioreg, 0x1c);
fan3pin = !(regval & (1 << 5));
......@@ -3215,7 +3245,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
fan4min = fan4pin;
if (data->kind == nct6791) {
if (data->kind == nct6791 || data->kind == nct6792) {
regval = superio_inb(sioreg, 0x2d);
fan6pin = (regval & (1 << 1));
pwm6pin = (regval & (1 << 0));
......@@ -3588,6 +3618,7 @@ static int nct6775_probe(struct platform_device *pdev)
break;
case nct6791:
case nct6792:
data->in_num = 15;
data->pwm_num = 6;
data->auto_pwm_num = 4;
......@@ -3650,12 +3681,20 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
data->REG_ALARM = NCT6791_REG_ALARM;
data->REG_BEEP = NCT6776_REG_BEEP;
if (data->kind == nct6791)
data->REG_BEEP = NCT6776_REG_BEEP;
else
data->REG_BEEP = NCT6792_REG_BEEP;
reg_temp = NCT6779_REG_TEMP;
reg_temp_mon = NCT6779_REG_TEMP_MON;
num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
if (data->kind == nct6791) {
reg_temp_mon = NCT6779_REG_TEMP_MON;
num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
} else {
reg_temp_mon = NCT6792_REG_TEMP_MON;
num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
}
reg_temp_over = NCT6779_REG_TEMP_OVER;
reg_temp_hyst = NCT6779_REG_TEMP_HYST;
reg_temp_config = NCT6779_REG_TEMP_CONFIG;
......@@ -3854,6 +3893,7 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6106:
case nct6779:
case nct6791:
case nct6792:
break;
}
......@@ -3885,6 +3925,7 @@ static int nct6775_probe(struct platform_device *pdev)
tmp |= 0x3e;
break;
case nct6791:
case nct6792:
tmp |= 0x7e;
break;
}
......@@ -3972,7 +4013,7 @@ static int nct6775_resume(struct device *dev)
mutex_lock(&data->update_lock);
data->bank = 0xff; /* Force initial bank selection */
if (data->kind == nct6791) {
if (data->kind == nct6791 || data->kind == nct6792) {
err = superio_enter(data->sioreg);
if (err)
goto abort;
......@@ -4052,6 +4093,7 @@ static const char * const nct6775_sio_names[] __initconst = {
"NCT6776D/F",
"NCT6779D",
"NCT6791D",
"NCT6792D",
};
/* nct6775_find() looks for a '627 in the Super-I/O config space */
......@@ -4086,6 +4128,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
case SIO_NCT6791_ID:
sio_data->kind = nct6791;
break;
case SIO_NCT6792_ID:
sio_data->kind = nct6792;
break;
default:
if (val != 0xffff)
pr_debug("unsupported chip ID: 0x%04x\n", val);
......@@ -4111,7 +4156,7 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
}
if (sio_data->kind == nct6791)
if (sio_data->kind == nct6791 || sio_data->kind == nct6792)
nct6791_enable_io_mapping(sioaddr);
superio_exit(sioaddr);
......@@ -4221,7 +4266,7 @@ static void __exit sensors_nct6775_exit(void)
}
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D driver");
MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D/NCT6792D driver");
MODULE_LICENSE("GPL");
module_init(sensors_nct6775_init);
......
/*
* nct7802 - Driver for Nuvoton NCT7802Y
*
* Copyright (C) 2014 Guenter Roeck <linux@roeck-us.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#define DRVNAME "nct7802"
static const u8 REG_VOLTAGE[5] = { 0x09, 0x0a, 0x0c, 0x0d, 0x0e };
static const u8 REG_VOLTAGE_LIMIT_LSB[2][5] = {
{ 0x40, 0x00, 0x42, 0x44, 0x46 },
{ 0x3f, 0x00, 0x41, 0x43, 0x45 },
};
static const u8 REG_VOLTAGE_LIMIT_MSB[5] = { 0x48, 0x00, 0x47, 0x47, 0x48 };
static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = {
{ 0, 0, 4, 0, 4 },
{ 2, 0, 6, 2, 6 },
};
#define REG_BANK 0x00
#define REG_TEMP_LSB 0x05
#define REG_TEMP_PECI_LSB 0x08
#define REG_VOLTAGE_LOW 0x0f
#define REG_FANCOUNT_LOW 0x13
#define REG_START 0x21
#define REG_MODE 0x22
#define REG_PECI_ENABLE 0x23
#define REG_FAN_ENABLE 0x24
#define REG_VMON_ENABLE 0x25
#define REG_VENDOR_ID 0xfd
#define REG_CHIP_ID 0xfe
#define REG_VERSION_ID 0xff
/*
* Data structures and manipulation thereof
*/
struct nct7802_data {
struct regmap *regmap;
struct mutex access_lock; /* for multi-byte read and write operations */
};
static int nct7802_read_temp(struct nct7802_data *data,
u8 reg_temp, u8 reg_temp_low, int *temp)
{
unsigned int t1, t2 = 0;
int err;
*temp = 0;
mutex_lock(&data->access_lock);
err = regmap_read(data->regmap, reg_temp, &t1);
if (err < 0)
goto abort;
t1 <<= 8;
if (reg_temp_low) { /* 11 bit data */
err = regmap_read(data->regmap, reg_temp_low, &t2);
if (err < 0)
goto abort;
}
t1 |= t2 & 0xe0;
*temp = (s16)t1 / 32 * 125;
abort:
mutex_unlock(&data->access_lock);
return err;
}
static int nct7802_read_fan(struct nct7802_data *data, u8 reg_fan)
{
unsigned int f1, f2;
int ret;
mutex_lock(&data->access_lock);
ret = regmap_read(data->regmap, reg_fan, &f1);
if (ret < 0)
goto abort;
ret = regmap_read(data->regmap, REG_FANCOUNT_LOW, &f2);
if (ret < 0)
goto abort;
ret = (f1 << 5) | (f2 >> 3);
/* convert fan count to rpm */
if (ret == 0x1fff) /* maximum value, assume fan is stopped */
ret = 0;
else if (ret)
ret = DIV_ROUND_CLOSEST(1350000U, ret);
abort:
mutex_unlock(&data->access_lock);
return ret;
}
static int nct7802_read_fan_min(struct nct7802_data *data, u8 reg_fan_low,
u8 reg_fan_high)
{
unsigned int f1, f2;
int ret;
mutex_lock(&data->access_lock);
ret = regmap_read(data->regmap, reg_fan_low, &f1);
if (ret < 0)
goto abort;
ret = regmap_read(data->regmap, reg_fan_high, &f2);
if (ret < 0)
goto abort;
ret = f1 | ((f2 & 0xf8) << 5);
/* convert fan count to rpm */
if (ret == 0x1fff) /* maximum value, assume no limit */
ret = 0;
else if (ret)
ret = DIV_ROUND_CLOSEST(1350000U, ret);
abort:
mutex_unlock(&data->access_lock);
return ret;
}
static int nct7802_write_fan_min(struct nct7802_data *data, u8 reg_fan_low,
u8 reg_fan_high, unsigned int limit)
{
int err;
if (limit)
limit = DIV_ROUND_CLOSEST(1350000U, limit);
else
limit = 0x1fff;
limit = clamp_val(limit, 0, 0x1fff);
mutex_lock(&data->access_lock);
err = regmap_write(data->regmap, reg_fan_low, limit & 0xff);
if (err < 0)
goto abort;
err = regmap_write(data->regmap, reg_fan_high, (limit & 0x1f00) >> 5);
abort:
mutex_unlock(&data->access_lock);
return err;
}
static u8 nct7802_vmul[] = { 4, 2, 2, 2, 2 };
static int nct7802_read_voltage(struct nct7802_data *data, int nr, int index)
{
unsigned int v1, v2;
int ret;
mutex_lock(&data->access_lock);
if (index == 0) { /* voltage */
ret = regmap_read(data->regmap, REG_VOLTAGE[nr], &v1);
if (ret < 0)
goto abort;
ret = regmap_read(data->regmap, REG_VOLTAGE_LOW, &v2);
if (ret < 0)
goto abort;
ret = ((v1 << 2) | (v2 >> 6)) * nct7802_vmul[nr];
} else { /* limit */
int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr];
ret = regmap_read(data->regmap,
REG_VOLTAGE_LIMIT_LSB[index - 1][nr], &v1);
if (ret < 0)
goto abort;
ret = regmap_read(data->regmap, REG_VOLTAGE_LIMIT_MSB[nr],
&v2);
if (ret < 0)
goto abort;
ret = (v1 | ((v2 << shift) & 0x300)) * nct7802_vmul[nr];
}
abort:
mutex_unlock(&data->access_lock);
return ret;
}
static int nct7802_write_voltage(struct nct7802_data *data, int nr, int index,
unsigned int voltage)
{
int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr];
int err;
voltage = DIV_ROUND_CLOSEST(voltage, nct7802_vmul[nr]);
voltage = clamp_val(voltage, 0, 0x3ff);
mutex_lock(&data->access_lock);
err = regmap_write(data->regmap,
REG_VOLTAGE_LIMIT_LSB[index - 1][nr],
voltage & 0xff);
if (err < 0)
goto abort;
err = regmap_update_bits(data->regmap, REG_VOLTAGE_LIMIT_MSB[nr],
0x0300 >> shift, (voltage & 0x0300) >> shift);
abort:
mutex_unlock(&data->access_lock);
return err;
}
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct nct7802_data *data = dev_get_drvdata(dev);
int voltage;
voltage = nct7802_read_voltage(data, sattr->nr, sattr->index);
if (voltage < 0)
return voltage;
return sprintf(buf, "%d\n", voltage);
}
static ssize_t store_in(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct nct7802_data *data = dev_get_drvdata(dev);
int index = sattr->index;
int nr = sattr->nr;
unsigned long val;
int err;
err = kstrtoul(buf, 10, &val);
if (err < 0)
return err;
err = nct7802_write_voltage(data, nr, index, val);
return err ? : count;
}
static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct nct7802_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int err, temp;
err = nct7802_read_temp(data, sattr->nr, sattr->index, &temp);
if (err < 0)
return err;
return sprintf(buf, "%d\n", temp);
}
static ssize_t store_temp(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct nct7802_data *data = dev_get_drvdata(dev);
int nr = sattr->nr;
long val;
int err;
err = kstrtol(buf, 10, &val);
if (err < 0)
return err;
val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
err = regmap_write(data->regmap, nr, val & 0xff);
return err ? : count;
}
static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
struct nct7802_data *data = dev_get_drvdata(dev);
int speed;
speed = nct7802_read_fan(data, sattr->index);
if (speed < 0)
return speed;
return sprintf(buf, "%d\n", speed);
}
static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct nct7802_data *data = dev_get_drvdata(dev);
int speed;
speed = nct7802_read_fan_min(data, sattr->nr, sattr->index);
if (speed < 0)
return speed;
return sprintf(buf, "%d\n", speed);
}
static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct nct7802_data *data = dev_get_drvdata(dev);
unsigned long val;
int err;
err = kstrtoul(buf, 10, &val);
if (err < 0)
return err;
err = nct7802_write_fan_min(data, sattr->nr, sattr->index, val);
return err ? : count;
}
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct nct7802_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int bit = sattr->index;
unsigned int val;
int ret;
ret = regmap_read(data->regmap, sattr->nr, &val);
if (ret < 0)
return ret;
return sprintf(buf, "%u\n", !!(val & (1 << bit)));
}
static ssize_t
show_beep(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct nct7802_data *data = dev_get_drvdata(dev);
unsigned int regval;
int err;
err = regmap_read(data->regmap, sattr->nr, &regval);
if (err)
return err;
return sprintf(buf, "%u\n", !!(regval & (1 << sattr->index)));
}
static ssize_t
store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct nct7802_data *data = dev_get_drvdata(dev);
unsigned long val;
int err;
err = kstrtoul(buf, 10, &val);
if (err < 0)
return err;
if (val > 1)
return -EINVAL;
err = regmap_update_bits(data->regmap, sattr->nr, 1 << sattr->index,
val ? 1 << sattr->index : 0);
return err ? : count;
}
static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0x01,
REG_TEMP_LSB);
static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x31, 0);
static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x30, 0);
static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x3a, 0);
static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0x02,
REG_TEMP_LSB);
static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x33, 0);
static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x32, 0);
static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x3b, 0);
static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0x03,
REG_TEMP_LSB);
static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x35, 0);
static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x34, 0);
static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x3c, 0);
static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 0x04, 0);
static SENSOR_DEVICE_ATTR_2(temp4_min, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x37, 0);
static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x36, 0);
static SENSOR_DEVICE_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x3d, 0);
static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 0x06,
REG_TEMP_PECI_LSB);
static SENSOR_DEVICE_ATTR_2(temp5_min, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x39, 0);
static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x38, 0);
static SENSOR_DEVICE_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp,
store_temp, 0x3e, 0);
static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 0x07,
REG_TEMP_PECI_LSB);
static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
0x18, 0);
static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_alarm, NULL,
0x18, 1);
static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_alarm, NULL,
0x18, 2);
static SENSOR_DEVICE_ATTR_2(temp4_min_alarm, S_IRUGO, show_alarm, NULL,
0x18, 3);
static SENSOR_DEVICE_ATTR_2(temp5_min_alarm, S_IRUGO, show_alarm, NULL,
0x18, 4);
static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
0x19, 0);
static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_alarm, NULL,
0x19, 1);
static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_alarm, NULL,
0x19, 2);
static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, show_alarm, NULL,
0x19, 3);
static SENSOR_DEVICE_ATTR_2(temp5_max_alarm, S_IRUGO, show_alarm, NULL,
0x19, 4);
static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
0x1b, 0);
static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
0x1b, 1);
static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_alarm, NULL,
0x1b, 2);
static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO, show_alarm, NULL,
0x1b, 3);
static SENSOR_DEVICE_ATTR_2(temp5_crit_alarm, S_IRUGO, show_alarm, NULL,
0x1b, 4);
static SENSOR_DEVICE_ATTR_2(temp1_fault, S_IRUGO, show_alarm, NULL, 0x17, 0);
static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_alarm, NULL, 0x17, 1);
static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_alarm, NULL, 0x17, 2);
static SENSOR_DEVICE_ATTR_2(temp1_beep, S_IRUGO | S_IWUSR, show_beep,
store_beep, 0x5c, 0);
static SENSOR_DEVICE_ATTR_2(temp2_beep, S_IRUGO | S_IWUSR, show_beep,
store_beep, 0x5c, 1);
static SENSOR_DEVICE_ATTR_2(temp3_beep, S_IRUGO | S_IWUSR, show_beep,
store_beep, 0x5c, 2);
static SENSOR_DEVICE_ATTR_2(temp4_beep, S_IRUGO | S_IWUSR, show_beep,
store_beep, 0x5c, 3);
static SENSOR_DEVICE_ATTR_2(temp5_beep, S_IRUGO | S_IWUSR, show_beep,
store_beep, 0x5c, 4);
static SENSOR_DEVICE_ATTR_2(temp6_beep, S_IRUGO | S_IWUSR, show_beep,
store_beep, 0x5c, 5);
static struct attribute *nct7802_temp_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_fault.dev_attr.attr,
&sensor_dev_attr_temp1_beep.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr, /* 9 */
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_beep.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr, /* 18 */
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_crit.dev_attr.attr,
&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp3_beep.dev_attr.attr,
&sensor_dev_attr_temp4_input.dev_attr.attr, /* 27 */
&sensor_dev_attr_temp4_min.dev_attr.attr,
&sensor_dev_attr_temp4_max.dev_attr.attr,
&sensor_dev_attr_temp4_crit.dev_attr.attr,
&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_beep.dev_attr.attr,
&sensor_dev_attr_temp5_input.dev_attr.attr, /* 35 */
&sensor_dev_attr_temp5_min.dev_attr.attr,
&sensor_dev_attr_temp5_max.dev_attr.attr,
&sensor_dev_attr_temp5_crit.dev_attr.attr,
&sensor_dev_attr_temp5_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp5_beep.dev_attr.attr,
&sensor_dev_attr_temp6_input.dev_attr.attr, /* 43 */
&sensor_dev_attr_temp6_beep.dev_attr.attr,
NULL
};
static umode_t nct7802_temp_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct nct7802_data *data = dev_get_drvdata(dev);
unsigned int reg;
int err;
err = regmap_read(data->regmap, REG_MODE, &reg);
if (err < 0)
return 0;
if (index < 9 &&
(reg & 03) != 0x01 && (reg & 0x03) != 0x02) /* RD1 */
return 0;
if (index >= 9 && index < 18 &&
(reg & 0x0c) != 0x04 && (reg & 0x0c) != 0x08) /* RD2 */
return 0;
if (index >= 18 && index < 27 && (reg & 0x30) != 0x10) /* RD3 */
return 0;
if (index >= 27 && index < 35) /* local */
return attr->mode;
err = regmap_read(data->regmap, REG_PECI_ENABLE, &reg);
if (err < 0)
return 0;
if (index >= 35 && index < 43 && !(reg & 0x01)) /* PECI 0 */
return 0;
if (index >= 0x43 && (!(reg & 0x02))) /* PECI 1 */
return 0;
return attr->mode;
}
static struct attribute_group nct7802_temp_group = {
.attrs = nct7802_temp_attrs,
.is_visible = nct7802_temp_is_visible,
};
static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0);
static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, store_in,
0, 1);
static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, store_in,
0, 2);
static SENSOR_DEVICE_ATTR_2(in0_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 3);
static SENSOR_DEVICE_ATTR_2(in0_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
0x5a, 3);
static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0);
static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0);
static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, store_in,
2, 1);
static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, store_in,
2, 2);
static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 0);
static SENSOR_DEVICE_ATTR_2(in2_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
0x5a, 0);
static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0);
static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, store_in,
3, 1);
static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, store_in,
3, 2);
static SENSOR_DEVICE_ATTR_2(in3_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 1);
static SENSOR_DEVICE_ATTR_2(in3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
0x5a, 1);
static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0);
static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, store_in,
4, 1);
static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, store_in,
4, 2);
static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 2);
static SENSOR_DEVICE_ATTR_2(in4_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
0x5a, 2);
static struct attribute *nct7802_in_attrs[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
&sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in0_beep.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr, /* 5 */
&sensor_dev_attr_in2_input.dev_attr.attr, /* 6 */
&sensor_dev_attr_in2_min.dev_attr.attr,
&sensor_dev_attr_in2_max.dev_attr.attr,
&sensor_dev_attr_in2_alarm.dev_attr.attr,
&sensor_dev_attr_in2_beep.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr, /* 11 */
&sensor_dev_attr_in3_min.dev_attr.attr,
&sensor_dev_attr_in3_max.dev_attr.attr,
&sensor_dev_attr_in3_alarm.dev_attr.attr,
&sensor_dev_attr_in3_beep.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr, /* 17 */
&sensor_dev_attr_in4_min.dev_attr.attr,
&sensor_dev_attr_in4_max.dev_attr.attr,
&sensor_dev_attr_in4_alarm.dev_attr.attr,
&sensor_dev_attr_in4_beep.dev_attr.attr,
NULL,
};
static umode_t nct7802_in_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct nct7802_data *data = dev_get_drvdata(dev);
unsigned int reg;
int err;
if (index < 6) /* VCC, VCORE */
return attr->mode;
err = regmap_read(data->regmap, REG_MODE, &reg);
if (err < 0)
return 0;
if (index >= 6 && index < 11 && (reg & 0x03) != 0x03) /* VSEN1 */
return 0;
if (index >= 11 && index < 17 && (reg & 0x0c) != 0x0c) /* VSEN2 */
return 0;
if (index >= 17 && (reg & 0x30) != 0x30) /* VSEN3 */
return 0;
return attr->mode;
}
static struct attribute_group nct7802_in_group = {
.attrs = nct7802_in_attrs,
.is_visible = nct7802_in_is_visible,
};
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0x10);
static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan_min,
store_fan_min, 0x49, 0x4c);
static SENSOR_DEVICE_ATTR_2(fan1_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 0);
static SENSOR_DEVICE_ATTR_2(fan1_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
0x5b, 0);
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 0x11);
static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan_min,
store_fan_min, 0x4a, 0x4d);
static SENSOR_DEVICE_ATTR_2(fan2_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 1);
static SENSOR_DEVICE_ATTR_2(fan2_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
0x5b, 1);
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 0x12);
static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan_min,
store_fan_min, 0x4b, 0x4e);
static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 2);
static SENSOR_DEVICE_ATTR_2(fan3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
0x5b, 2);
static struct attribute *nct7802_fan_attrs[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_alarm.dev_attr.attr,
&sensor_dev_attr_fan1_beep.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_alarm.dev_attr.attr,
&sensor_dev_attr_fan2_beep.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_alarm.dev_attr.attr,
&sensor_dev_attr_fan3_beep.dev_attr.attr,
NULL
};
static umode_t nct7802_fan_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct nct7802_data *data = dev_get_drvdata(dev);
int fan = index / 4; /* 4 attributes per fan */
unsigned int reg;
int err;
err = regmap_read(data->regmap, REG_FAN_ENABLE, &reg);
if (err < 0 || !(reg & (1 << fan)))
return 0;
return attr->mode;
}
static struct attribute_group nct7802_fan_group = {
.attrs = nct7802_fan_attrs,
.is_visible = nct7802_fan_is_visible,
};
static const struct attribute_group *nct7802_groups[] = {
&nct7802_temp_group,
&nct7802_in_group,
&nct7802_fan_group,
NULL
};
static int nct7802_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
int reg;
/*
* Chip identification registers are only available in bank 0,
* so only attempt chip detection if bank 0 is selected
*/
reg = i2c_smbus_read_byte_data(client, REG_BANK);
if (reg != 0x00)
return -ENODEV;
reg = i2c_smbus_read_byte_data(client, REG_VENDOR_ID);
if (reg != 0x50)
return -ENODEV;
reg = i2c_smbus_read_byte_data(client, REG_CHIP_ID);
if (reg != 0xc3)
return -ENODEV;
reg = i2c_smbus_read_byte_data(client, REG_VERSION_ID);
if (reg < 0 || (reg & 0xf0) != 0x20)
return -ENODEV;
/* Also validate lower bits of voltage and temperature registers */
reg = i2c_smbus_read_byte_data(client, REG_TEMP_LSB);
if (reg < 0 || (reg & 0x1f))
return -ENODEV;
reg = i2c_smbus_read_byte_data(client, REG_TEMP_PECI_LSB);
if (reg < 0 || (reg & 0x3f))
return -ENODEV;
reg = i2c_smbus_read_byte_data(client, REG_VOLTAGE_LOW);
if (reg < 0 || (reg & 0x3f))
return -ENODEV;
strlcpy(info->type, "nct7802", I2C_NAME_SIZE);
return 0;
}
static bool nct7802_regmap_is_volatile(struct device *dev, unsigned int reg)
{
return reg != REG_BANK && reg <= 0x20;
}
static struct regmap_config nct7802_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = nct7802_regmap_is_volatile,
};
static int nct7802_init_chip(struct nct7802_data *data)
{
int err;
/* Enable ADC */
err = regmap_update_bits(data->regmap, REG_START, 0x01, 0x01);
if (err)
return err;
/* Enable local temperature sensor */
err = regmap_update_bits(data->regmap, REG_MODE, 0x40, 0x40);
if (err)
return err;
/* Enable Vcore and VCC voltage monitoring */
return regmap_update_bits(data->regmap, REG_VMON_ENABLE, 0x03, 0x03);
}
static int nct7802_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct nct7802_data *data;
struct device *hwmon_dev;
int ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
data->regmap = devm_regmap_init_i2c(client, &nct7802_regmap_config);
if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap);
mutex_init(&data->access_lock);
ret = nct7802_init_chip(data);
if (ret < 0)
return ret;
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
data,
nct7802_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const unsigned short nct7802_address_list[] = {
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END
};
static const struct i2c_device_id nct7802_idtable[] = {
{ "nct7802", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, nct7802_idtable);
static struct i2c_driver nct7802_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = DRVNAME,
},
.detect = nct7802_detect,
.probe = nct7802_probe,
.id_table = nct7802_idtable,
.address_list = nct7802_address_list,
};
module_i2c_driver(nct7802_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
MODULE_DESCRIPTION("NCT7802Y Hardware Monitoring Driver");
MODULE_LICENSE("GPL v2");
......@@ -47,15 +47,22 @@ config SENSORS_LM25066
be called lm25066.
config SENSORS_LTC2978
tristate "Linear Technologies LTC2974, LTC2978, LTC3880, and LTC3883"
tristate "Linear Technologies LTC2978 and compatibles"
default n
help
If you say yes here you get hardware monitoring support for Linear
Technology LTC2974, LTC2978, LTC3880, and LTC3883.
Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676.
This driver can also be built as a module. If so, the module will
be called ltc2978.
config SENSORS_LTC2978_REGULATOR
boolean "Regulator support for LTC2978 and compatibles"
depends on SENSORS_LTC2978 && REGULATOR
help
If you say yes here you get regulator support for Linear
Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676.
config SENSORS_MAX16064
tristate "Maxim MAX16064"
default n
......
......@@ -22,6 +22,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/regulator/driver.h>
#include "pmbus.h"
enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 };
......@@ -374,6 +375,19 @@ static const struct i2c_device_id ltc2978_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
#if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
static const struct regulator_desc ltc2978_reg_desc[] = {
PMBUS_REGULATOR("vout", 0),
PMBUS_REGULATOR("vout", 1),
PMBUS_REGULATOR("vout", 2),
PMBUS_REGULATOR("vout", 3),
PMBUS_REGULATOR("vout", 4),
PMBUS_REGULATOR("vout", 5),
PMBUS_REGULATOR("vout", 6),
PMBUS_REGULATOR("vout", 7),
};
#endif /* CONFIG_SENSORS_LTC2978_REGULATOR */
static int ltc2978_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......@@ -487,13 +501,36 @@ static int ltc2978_probe(struct i2c_client *client,
default:
return -ENODEV;
}
#if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
info->num_regulators = info->pages;
info->reg_desc = ltc2978_reg_desc;
if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc)) {
dev_err(&client->dev, "num_regulators too large!");
info->num_regulators = ARRAY_SIZE(ltc2978_reg_desc);
}
#endif
return pmbus_do_probe(client, id, info);
}
/* This is the driver that will be inserted */
#ifdef CONFIG_OF
static const struct of_device_id ltc2978_of_match[] = {
{ .compatible = "lltc,ltc2974" },
{ .compatible = "lltc,ltc2977" },
{ .compatible = "lltc,ltc2978" },
{ .compatible = "lltc,ltc3880" },
{ .compatible = "lltc,ltc3883" },
{ .compatible = "lltc,ltm4676" },
{ }
};
MODULE_DEVICE_TABLE(of, ltc2978_of_match);
#endif
static struct i2c_driver ltc2978_driver = {
.driver = {
.name = "ltc2978",
.of_match_table = of_match_ptr(ltc2978_of_match),
},
.probe = ltc2978_probe,
.remove = pmbus_do_remove,
......
......@@ -19,6 +19,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/regulator/driver.h>
#ifndef PMBUS_H
#define PMBUS_H
......@@ -185,6 +187,11 @@
#define PMBUS_VIRT_VMON_OV_FAULT_LIMIT (PMBUS_VIRT_BASE + 34)
#define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 35)
/*
* OPERATION
*/
#define PB_OPERATION_CONTROL_ON (1<<7)
/*
* CAPABILITY
*/
......@@ -365,8 +372,27 @@ struct pmbus_driver_info {
*/
int (*identify)(struct i2c_client *client,
struct pmbus_driver_info *info);
/* Regulator functionality, if supported by this chip driver. */
int num_regulators;
const struct regulator_desc *reg_desc;
};
/* Regulator ops */
extern struct regulator_ops pmbus_regulator_ops;
/* Macro for filling in array of struct regulator_desc */
#define PMBUS_REGULATOR(_name, _id) \
[_id] = { \
.name = (_name # _id), \
.id = (_id), \
.of_match = of_match_ptr(_name # _id), \
.regulators_node = of_match_ptr("regulators"), \
.ops = &pmbus_regulator_ops, \
.owner = THIS_MODULE, \
}
/* Function declarations */
void pmbus_clear_cache(struct i2c_client *client);
......@@ -375,6 +401,10 @@ int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg,
u8 value);
int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
u8 mask, u8 value);
void pmbus_clear_faults(struct i2c_client *client);
bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
......
......@@ -29,6 +29,8 @@
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/i2c/pmbus.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include "pmbus.h"
/*
......@@ -253,6 +255,37 @@ int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
}
EXPORT_SYMBOL_GPL(pmbus_read_byte_data);
int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value)
{
int rv;
rv = pmbus_set_page(client, page);
if (rv < 0)
return rv;
return i2c_smbus_write_byte_data(client, reg, value);
}
EXPORT_SYMBOL_GPL(pmbus_write_byte_data);
int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
u8 mask, u8 value)
{
unsigned int tmp;
int rv;
rv = pmbus_read_byte_data(client, page, reg);
if (rv < 0)
return rv;
tmp = (rv & ~mask) | (value & mask);
if (tmp != rv)
rv = pmbus_write_byte_data(client, page, reg, tmp);
return rv;
}
EXPORT_SYMBOL_GPL(pmbus_update_byte_data);
/*
* _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if
* a device specific mapping function exists and calls it if necessary.
......@@ -1727,6 +1760,84 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
return 0;
}
#if IS_ENABLED(CONFIG_REGULATOR)
static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
{
struct device *dev = rdev_get_dev(rdev);
struct i2c_client *client = to_i2c_client(dev->parent);
u8 page = rdev_get_id(rdev);
int ret;
ret = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
if (ret < 0)
return ret;
return !!(ret & PB_OPERATION_CONTROL_ON);
}
static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
{
struct device *dev = rdev_get_dev(rdev);
struct i2c_client *client = to_i2c_client(dev->parent);
u8 page = rdev_get_id(rdev);
return pmbus_update_byte_data(client, page, PMBUS_OPERATION,
PB_OPERATION_CONTROL_ON,
enable ? PB_OPERATION_CONTROL_ON : 0);
}
static int pmbus_regulator_enable(struct regulator_dev *rdev)
{
return _pmbus_regulator_on_off(rdev, 1);
}
static int pmbus_regulator_disable(struct regulator_dev *rdev)
{
return _pmbus_regulator_on_off(rdev, 0);
}
struct regulator_ops pmbus_regulator_ops = {
.enable = pmbus_regulator_enable,
.disable = pmbus_regulator_disable,
.is_enabled = pmbus_regulator_is_enabled,
};
EXPORT_SYMBOL_GPL(pmbus_regulator_ops);
static int pmbus_regulator_register(struct pmbus_data *data)
{
struct device *dev = data->dev;
const struct pmbus_driver_info *info = data->info;
const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
struct regulator_dev *rdev;
int i;
for (i = 0; i < info->num_regulators; i++) {
struct regulator_config config = { };
config.dev = dev;
config.driver_data = data;
if (pdata && pdata->reg_init_data)
config.init_data = &pdata->reg_init_data[i];
rdev = devm_regulator_register(dev, &info->reg_desc[i],
&config);
if (IS_ERR(rdev)) {
dev_err(dev, "Failed to register %s regulator\n",
info->reg_desc[i].name);
return PTR_ERR(rdev);
}
}
return 0;
}
#else
static int pmbus_regulator_register(struct pmbus_data *data)
{
return 0;
}
#endif
int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
struct pmbus_driver_info *info)
{
......@@ -1781,8 +1892,15 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
dev_err(dev, "Failed to register hwmon device\n");
goto out_kfree;
}
ret = pmbus_regulator_register(data);
if (ret)
goto out_unregister;
return 0;
out_unregister:
hwmon_device_unregister(data->hwmon_dev);
out_kfree:
kfree(data->group.attrs);
return ret;
......
......@@ -44,9 +44,10 @@
#include <linux/sysfs.h>
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
static const unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4c, 0x4d,
0x4e, 0x4f, I2C_CLIENT_END };
enum chips { tmp401, tmp411, tmp431, tmp432 };
enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 };
/*
* The TMP401 registers, note some registers have different addresses for
......@@ -136,6 +137,7 @@ static const u8 TMP432_STATUS_REG[] = {
#define TMP411C_DEVICE_ID 0x10
#define TMP431_DEVICE_ID 0x31
#define TMP432_DEVICE_ID 0x32
#define TMP435_DEVICE_ID 0x35
/*
* Driver data (common to all clients)
......@@ -146,6 +148,7 @@ static const struct i2c_device_id tmp401_id[] = {
{ "tmp411", tmp411 },
{ "tmp431", tmp431 },
{ "tmp432", tmp432 },
{ "tmp435", tmp435 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp401_id);
......@@ -613,10 +616,10 @@ static const struct attribute_group tmp432_group = {
* Begin non sysfs callback code (aka Real code)
*/
static void tmp401_init_client(struct tmp401_data *data,
struct i2c_client *client)
static int tmp401_init_client(struct tmp401_data *data,
struct i2c_client *client)
{
int config, config_orig;
int config, config_orig, status = 0;
/* Set the conversion rate to 2 Hz */
i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
......@@ -624,16 +627,18 @@ static void tmp401_init_client(struct tmp401_data *data,
/* Start conversions (disable shutdown if necessary) */
config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
if (config < 0) {
dev_warn(&client->dev, "Initialization failed!\n");
return;
}
if (config < 0)
return config;
config_orig = config;
config &= ~TMP401_CONFIG_SHUTDOWN;
if (config != config_orig)
i2c_smbus_write_byte_data(client, TMP401_CONFIG_WRITE, config);
status = i2c_smbus_write_byte_data(client,
TMP401_CONFIG_WRITE,
config);
return status;
}
static int tmp401_detect(struct i2c_client *client,
......@@ -675,15 +680,18 @@ static int tmp401_detect(struct i2c_client *client,
kind = tmp411;
break;
case TMP431_DEVICE_ID:
if (client->addr == 0x4e)
if (client->addr != 0x4c && client->addr != 0x4d)
return -ENODEV;
kind = tmp431;
break;
case TMP432_DEVICE_ID:
if (client->addr == 0x4e)
if (client->addr != 0x4c && client->addr != 0x4d)
return -ENODEV;
kind = tmp432;
break;
case TMP435_DEVICE_ID:
kind = tmp435;
break;
default:
return -ENODEV;
}
......@@ -705,11 +713,13 @@ static int tmp401_detect(struct i2c_client *client,
static int tmp401_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const char *names[] = { "TMP401", "TMP411", "TMP431", "TMP432" };
static const char * const names[] = {
"TMP401", "TMP411", "TMP431", "TMP432", "TMP435"
};
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct tmp401_data *data;
int groups = 0;
int groups = 0, status;
data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL);
if (!data)
......@@ -720,7 +730,9 @@ static int tmp401_probe(struct i2c_client *client,
data->kind = id->driver_data;
/* Initialize the TMP401 chip */
tmp401_init_client(data, client);
status = tmp401_init_client(data, client);
if (status < 0)
return status;
/* Register sysfs hooks */
data->groups[groups++] = &tmp401_group;
......
......@@ -40,6 +40,10 @@
struct pmbus_platform_data {
u32 flags; /* Device specific flags */
/* regulator support */
int num_regulators;
struct regulator_init_data *reg_init_data;
};
#endif /* _PMBUS_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment