You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'hwmon-for-linus-v4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
Pull hwmon updates from Guenter Roeck: - New hwmon registration API, including ports of several drivers to the new API - New hwmon driver for APM X-Gene SoC - Added support for UCD90160, DPS-460, DPS-800, and SGD009 PMBUs chips - Various cleanups, minor improvements, and fixes in several drivers * tag 'hwmon-for-linus-v4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (54 commits) hwmon: (nct6775) Add support for multiple virtual temperature sources hwmon: (adt7470) No need for additional synchronization on kthread_stop() hwmon: (lm95241) Update module description to include LM95231 hwmon: (lm95245) Select REGMAP_I2C hwmon: (ibmpowernv) Fix label for cores numbers not threads hwmon: (adt7470) Allow faster removal hwmon: (adt7470) Add write support to alarm_mask hwmon: (xgene) access mailbox as RAM hwmon: (lm95245) Use new hwmon registration API hwmon: (lm95241) Convert to use new hwmon registration API hwmon: (jc42) Convert to use new hwmon registration API hwmon: (max31790) Convert to use new hwmon registration API hwmon: (nct7904) Convert to use new hwmon registration API hwmon: (ltc4245) Convert to use new hwmon registration API hwmon: (tmp421) Convert to use new hwmon registration API hwmon: (tmp102) Convert to use new hwmon registration API hwmon: (lm90) Convert to use new hwmon registration API hwmon: (lm75) Convert to use new hwmon registration API hwmon: (xgene) Fix crash when alarm occurs before driver probe hwmon: (iio_hwmon) defer probe when no channel is found ...
This commit is contained in:
@@ -969,7 +969,6 @@ config SENSORS_LM73
|
||||
config SENSORS_LM75
|
||||
tristate "National Semiconductor LM75 and compatibles"
|
||||
depends on I2C
|
||||
depends on THERMAL || !THERMAL_OF
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for one common type of
|
||||
@@ -1119,6 +1118,7 @@ config SENSORS_LM95241
|
||||
config SENSORS_LM95245
|
||||
tristate "National Semiconductor LM95245 and compatibles"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for LM95235 and LM95245
|
||||
temperature sensor chips.
|
||||
@@ -1572,7 +1572,6 @@ config SENSORS_THMC50
|
||||
config SENSORS_TMP102
|
||||
tristate "Texas Instruments TMP102"
|
||||
depends on I2C
|
||||
depends on THERMAL || !THERMAL_OF
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for Texas Instruments TMP102
|
||||
@@ -1823,6 +1822,13 @@ config SENSORS_ULTRA45
|
||||
This driver provides support for the Ultra45 workstation environmental
|
||||
sensors.
|
||||
|
||||
config SENSORS_XGENE
|
||||
tristate "APM X-Gene SoC hardware monitoring driver"
|
||||
depends on XGENE_SLIMPRO_MBOX || PCC
|
||||
help
|
||||
If you say yes here you get support for the temperature
|
||||
and power sensors for APM X-Gene SoC.
|
||||
|
||||
if ACPI
|
||||
|
||||
comment "ACPI drivers"
|
||||
|
||||
@@ -165,6 +165,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
|
||||
obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
|
||||
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o
|
||||
|
||||
obj-$(CONFIG_PMBUS) += pmbus/
|
||||
|
||||
|
||||
+42
-7
@@ -7,8 +7,7 @@
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* TODO: SPI, support for external temperature sensor
|
||||
* use power-down mode for suspend?, interrupt handling?
|
||||
* TODO: SPI, use power-down mode for suspend?, interrupt handling?
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -31,6 +30,7 @@
|
||||
#define ADT7411_REG_CFG1 0x18
|
||||
#define ADT7411_CFG1_START_MONITOR (1 << 0)
|
||||
#define ADT7411_CFG1_RESERVED_BIT1 (1 << 1)
|
||||
#define ADT7411_CFG1_EXT_TDM (1 << 2)
|
||||
#define ADT7411_CFG1_RESERVED_BIT3 (1 << 3)
|
||||
|
||||
#define ADT7411_REG_CFG2 0x19
|
||||
@@ -57,6 +57,7 @@ struct adt7411_data {
|
||||
unsigned long next_update;
|
||||
int vref_cached;
|
||||
struct i2c_client *client;
|
||||
bool use_ext_temp;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -127,11 +128,20 @@ static ssize_t adt7411_show_vdd(struct device *dev,
|
||||
static ssize_t adt7411_show_temp(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int nr = to_sensor_dev_attr(attr)->index;
|
||||
struct adt7411_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int val = adt7411_read_10_bit(client, ADT7411_REG_INT_TEMP_VDD_LSB,
|
||||
ADT7411_REG_INT_TEMP_MSB, 0);
|
||||
int val;
|
||||
struct {
|
||||
u8 low;
|
||||
u8 high;
|
||||
} reg[2] = {
|
||||
{ ADT7411_REG_INT_TEMP_VDD_LSB, ADT7411_REG_INT_TEMP_MSB },
|
||||
{ ADT7411_REG_EXT_TEMP_AIN14_LSB,
|
||||
ADT7411_REG_EXT_TEMP_AIN1_MSB },
|
||||
};
|
||||
|
||||
val = adt7411_read_10_bit(client, reg[nr].low, reg[nr].high, 0);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
@@ -218,11 +228,13 @@ static ssize_t adt7411_set_bit(struct device *dev,
|
||||
return ret < 0 ? ret : count;
|
||||
}
|
||||
|
||||
|
||||
#define ADT7411_BIT_ATTR(__name, __reg, __bit) \
|
||||
SENSOR_DEVICE_ATTR_2(__name, S_IRUGO | S_IWUSR, adt7411_show_bit, \
|
||||
adt7411_set_bit, __bit, __reg)
|
||||
|
||||
static DEVICE_ATTR(temp1_input, S_IRUGO, adt7411_show_temp, NULL);
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7411_show_temp, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, adt7411_show_temp, NULL, 1);
|
||||
static DEVICE_ATTR(in0_input, S_IRUGO, adt7411_show_vdd, NULL);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, adt7411_show_input, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, adt7411_show_input, NULL, 1);
|
||||
@@ -237,7 +249,8 @@ static ADT7411_BIT_ATTR(fast_sampling, ADT7411_REG_CFG3, ADT7411_CFG3_ADC_CLK_22
|
||||
static ADT7411_BIT_ATTR(adc_ref_vdd, ADT7411_REG_CFG3, ADT7411_CFG3_REF_VDD);
|
||||
|
||||
static struct attribute *adt7411_attrs[] = {
|
||||
&dev_attr_temp1_input.attr,
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||
&dev_attr_in0_input.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
@@ -253,7 +266,27 @@ static struct attribute *adt7411_attrs[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
ATTRIBUTE_GROUPS(adt7411);
|
||||
static umode_t adt7411_attrs_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int index)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct adt7411_data *data = dev_get_drvdata(dev);
|
||||
bool visible = true;
|
||||
|
||||
if (attr == &sensor_dev_attr_temp2_input.dev_attr.attr)
|
||||
visible = data->use_ext_temp;
|
||||
else if (attr == &sensor_dev_attr_in1_input.dev_attr.attr ||
|
||||
attr == &sensor_dev_attr_in2_input.dev_attr.attr)
|
||||
visible = !data->use_ext_temp;
|
||||
|
||||
return visible ? attr->mode : 0;
|
||||
}
|
||||
|
||||
static const struct attribute_group adt7411_group = {
|
||||
.attrs = adt7411_attrs,
|
||||
.is_visible = adt7411_attrs_visible,
|
||||
};
|
||||
__ATTRIBUTE_GROUPS(adt7411);
|
||||
|
||||
static int adt7411_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info)
|
||||
@@ -309,6 +342,8 @@ static int adt7411_init_device(struct adt7411_data *data)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
data->use_ext_temp = ret & ADT7411_CFG1_EXT_TDM;
|
||||
|
||||
/*
|
||||
* We must only write zero to bit 1 and only one to bit 3 according to
|
||||
* the datasheet.
|
||||
|
||||
+102
-6
@@ -32,6 +32,7 @@
|
||||
#include <linux/log2.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
/* Addresses to scan */
|
||||
static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
|
||||
@@ -83,6 +84,7 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
|
||||
#define ADT7470_REG_PWM_MIN_MAX_ADDR 0x6D
|
||||
#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR 0x6E
|
||||
#define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR 0x71
|
||||
#define ADT7470_REG_CFG_2 0x74
|
||||
#define ADT7470_REG_ACOUSTICS12 0x75
|
||||
#define ADT7470_REG_ACOUSTICS34 0x76
|
||||
#define ADT7470_REG_DEVICE 0x3D
|
||||
@@ -142,6 +144,11 @@ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
|
||||
#define FAN_PERIOD_INVALID 65535
|
||||
#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
|
||||
|
||||
/* Config registers 1 and 2 include fields for selecting the PWM frequency */
|
||||
#define ADT7470_CFG_LF 0x40
|
||||
#define ADT7470_FREQ_MASK 0x70
|
||||
#define ADT7470_FREQ_SHIFT 4
|
||||
|
||||
struct adt7470_data {
|
||||
struct i2c_client *client;
|
||||
struct mutex lock;
|
||||
@@ -170,7 +177,6 @@ struct adt7470_data {
|
||||
u8 pwm_auto_temp[ADT7470_PWM_COUNT];
|
||||
|
||||
struct task_struct *auto_update;
|
||||
struct completion auto_update_stop;
|
||||
unsigned int auto_update_interval;
|
||||
};
|
||||
|
||||
@@ -266,12 +272,14 @@ static int adt7470_update_thread(void *p)
|
||||
mutex_lock(&data->lock);
|
||||
adt7470_read_temperatures(client, data);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
msleep_interruptible(data->auto_update_interval);
|
||||
|
||||
schedule_timeout(msecs_to_jiffies(data->auto_update_interval));
|
||||
}
|
||||
|
||||
complete_all(&data->auto_update_stop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -538,6 +546,28 @@ static ssize_t show_alarm_mask(struct device *dev,
|
||||
return sprintf(buf, "%x\n", data->alarms_mask);
|
||||
}
|
||||
|
||||
static ssize_t set_alarm_mask(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
long mask;
|
||||
|
||||
if (kstrtoul(buf, 0, &mask))
|
||||
return -EINVAL;
|
||||
|
||||
if (mask & ~0xffff)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
data->alarms_mask = mask;
|
||||
adt7470_write_word_data(data->client, ADT7470_REG_ALARM1_MASK, mask);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_fan_max(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
char *buf)
|
||||
@@ -688,6 +718,70 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
|
||||
return count;
|
||||
}
|
||||
|
||||
/* These are the valid PWM frequencies to the nearest Hz */
|
||||
static const int adt7470_freq_map[] = {
|
||||
11, 15, 22, 29, 35, 44, 59, 88, 1400, 22500
|
||||
};
|
||||
|
||||
static ssize_t show_pwm_freq(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct adt7470_data *data = adt7470_update_device(dev);
|
||||
unsigned char cfg_reg_1;
|
||||
unsigned char cfg_reg_2;
|
||||
int index;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
cfg_reg_1 = i2c_smbus_read_byte_data(data->client, ADT7470_REG_CFG);
|
||||
cfg_reg_2 = i2c_smbus_read_byte_data(data->client, ADT7470_REG_CFG_2);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
index = (cfg_reg_2 & ADT7470_FREQ_MASK) >> ADT7470_FREQ_SHIFT;
|
||||
if (!(cfg_reg_1 & ADT7470_CFG_LF))
|
||||
index += 8;
|
||||
if (index >= ARRAY_SIZE(adt7470_freq_map))
|
||||
index = ARRAY_SIZE(adt7470_freq_map) - 1;
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d\n", adt7470_freq_map[index]);
|
||||
}
|
||||
|
||||
static ssize_t set_pwm_freq(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct adt7470_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
long freq;
|
||||
int index;
|
||||
int low_freq = ADT7470_CFG_LF;
|
||||
unsigned char val;
|
||||
|
||||
if (kstrtol(buf, 10, &freq))
|
||||
return -EINVAL;
|
||||
|
||||
/* Round the user value given to the closest available frequency */
|
||||
index = find_closest(freq, adt7470_freq_map,
|
||||
ARRAY_SIZE(adt7470_freq_map));
|
||||
|
||||
if (index >= 8) {
|
||||
index -= 8;
|
||||
low_freq = 0;
|
||||
}
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
/* Configuration Register 1 */
|
||||
val = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
|
||||
i2c_smbus_write_byte_data(client, ADT7470_REG_CFG,
|
||||
(val & ~ADT7470_CFG_LF) | low_freq);
|
||||
/* Configuration Register 2 */
|
||||
val = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG_2);
|
||||
i2c_smbus_write_byte_data(client, ADT7470_REG_CFG_2,
|
||||
(val & ~ADT7470_FREQ_MASK) | (index << ADT7470_FREQ_SHIFT));
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_pwm_max(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
char *buf)
|
||||
@@ -918,7 +1012,8 @@ static ssize_t show_alarm(struct device *dev,
|
||||
return sprintf(buf, "0\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarm_mask, NULL);
|
||||
static DEVICE_ATTR(alarm_mask, S_IWUSR | S_IRUGO, show_alarm_mask,
|
||||
set_alarm_mask);
|
||||
static DEVICE_ATTR(num_temp_sensors, S_IWUSR | S_IRUGO, show_num_temp_sensors,
|
||||
set_num_temp_sensors);
|
||||
static DEVICE_ATTR(auto_update_interval, S_IWUSR | S_IRUGO,
|
||||
@@ -1038,6 +1133,8 @@ static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1);
|
||||
static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2);
|
||||
static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3);
|
||||
|
||||
static DEVICE_ATTR(pwm1_freq, S_IWUSR | S_IRUGO, show_pwm_freq, set_pwm_freq);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
|
||||
show_pwm_min, set_pwm_min, 0);
|
||||
static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO,
|
||||
@@ -1154,6 +1251,7 @@ static struct attribute *adt7470_attrs[] = {
|
||||
&sensor_dev_attr_fan4_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_force_pwm_max.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||
&dev_attr_pwm1_freq.attr,
|
||||
&sensor_dev_attr_pwm2.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm3.dev_attr.attr,
|
||||
&sensor_dev_attr_pwm4.dev_attr.attr,
|
||||
@@ -1256,7 +1354,6 @@ static int adt7470_probe(struct i2c_client *client,
|
||||
if (IS_ERR(hwmon_dev))
|
||||
return PTR_ERR(hwmon_dev);
|
||||
|
||||
init_completion(&data->auto_update_stop);
|
||||
data->auto_update = kthread_run(adt7470_update_thread, client, "%s",
|
||||
dev_name(hwmon_dev));
|
||||
if (IS_ERR(data->auto_update)) {
|
||||
@@ -1271,7 +1368,6 @@ static int adt7470_remove(struct i2c_client *client)
|
||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||
|
||||
kthread_stop(data->auto_update);
|
||||
wait_for_completion(&data->auto_update_stop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,10 @@
|
||||
#define FTS_EVENT_STATUS_REG 0x0006
|
||||
#define FTS_GLOBAL_CONTROL_REG 0x0007
|
||||
|
||||
#define FTS_DEVICE_DETECT_REG_1 0x0C
|
||||
#define FTS_DEVICE_DETECT_REG_2 0x0D
|
||||
#define FTS_DEVICE_DETECT_REG_3 0x0E
|
||||
|
||||
#define FTS_SENSOR_EVENT_REG 0x0010
|
||||
|
||||
#define FTS_FAN_EVENT_REG 0x0014
|
||||
@@ -54,6 +58,8 @@
|
||||
#define FTS_NO_TEMP_SENSORS 0x10
|
||||
#define FTS_NO_VOLT_SENSORS 0x04
|
||||
|
||||
static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
|
||||
|
||||
static struct i2c_device_id fts_id[] = {
|
||||
{ "ftsteutates", 0 },
|
||||
{ }
|
||||
@@ -734,6 +740,42 @@ static const struct attribute_group *fts_attr_groups[] = {
|
||||
/*****************************************************************************/
|
||||
/* Module initialization / remove functions */
|
||||
/*****************************************************************************/
|
||||
static int fts_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info)
|
||||
{
|
||||
int val;
|
||||
|
||||
/* detection works with revsion greater or equal to 0x2b */
|
||||
val = i2c_smbus_read_byte_data(client, FTS_DEVICE_REVISION_REG);
|
||||
if (val < 0x2b)
|
||||
return -ENODEV;
|
||||
|
||||
/* Device Detect Regs must have 0x17 0x34 and 0x54 */
|
||||
val = i2c_smbus_read_byte_data(client, FTS_DEVICE_DETECT_REG_1);
|
||||
if (val != 0x17)
|
||||
return -ENODEV;
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, FTS_DEVICE_DETECT_REG_2);
|
||||
if (val != 0x34)
|
||||
return -ENODEV;
|
||||
|
||||
val = i2c_smbus_read_byte_data(client, FTS_DEVICE_DETECT_REG_3);
|
||||
if (val != 0x54)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* 0x10 == Baseboard Management Controller, 0x01 == Teutates
|
||||
* Device ID Reg needs to be 0x11
|
||||
*/
|
||||
val = i2c_smbus_read_byte_data(client, FTS_DEVICE_ID_REG);
|
||||
if (val != 0x11)
|
||||
return -ENODEV;
|
||||
|
||||
strlcpy(info->type, fts_id[0].name, I2C_NAME_SIZE);
|
||||
info->flags = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fts_remove(struct i2c_client *client)
|
||||
{
|
||||
struct fts_data *data = dev_get_drvdata(&client->dev);
|
||||
@@ -804,12 +846,15 @@ static int fts_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
/* Module Details */
|
||||
/*****************************************************************************/
|
||||
static struct i2c_driver fts_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "ftsteutates",
|
||||
},
|
||||
.id_table = fts_id,
|
||||
.probe = fts_probe,
|
||||
.remove = fts_remove,
|
||||
.detect = fts_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
module_i2c_driver(fts_driver);
|
||||
|
||||
+593
-41
File diff suppressed because it is too large
Load Diff
@@ -143,13 +143,11 @@ static void __init make_sensor_label(struct device_node *np,
|
||||
if (cpuid >= 0)
|
||||
/*
|
||||
* The digital thermal sensors are associated
|
||||
* with a core. Let's print out the range of
|
||||
* cpu ids corresponding to the hardware
|
||||
* threads of the core.
|
||||
* with a core.
|
||||
*/
|
||||
n += snprintf(sdata->label + n,
|
||||
sizeof(sdata->label) - n, " %d-%d",
|
||||
cpuid, cpuid + threads_per_core - 1);
|
||||
sizeof(sdata->label) - n, " %d",
|
||||
cpuid);
|
||||
else
|
||||
n += snprintf(sdata->label + n,
|
||||
sizeof(sdata->label) - n, " phy%d", id);
|
||||
|
||||
@@ -73,8 +73,11 @@ static int iio_hwmon_probe(struct platform_device *pdev)
|
||||
name = dev->of_node->name;
|
||||
|
||||
channels = iio_channel_get_all(dev);
|
||||
if (IS_ERR(channels))
|
||||
if (IS_ERR(channels)) {
|
||||
if (PTR_ERR(channels) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
return PTR_ERR(channels);
|
||||
}
|
||||
|
||||
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
|
||||
if (st == NULL) {
|
||||
|
||||
@@ -2011,10 +2011,10 @@ static struct attribute *it87_attributes_in[] = {
|
||||
&sensor_dev_attr_in7_beep.dev_attr.attr, /* 39 */
|
||||
|
||||
&sensor_dev_attr_in8_input.dev_attr.attr, /* 40 */
|
||||
&sensor_dev_attr_in9_input.dev_attr.attr, /* 41 */
|
||||
&sensor_dev_attr_in10_input.dev_attr.attr, /* 41 */
|
||||
&sensor_dev_attr_in11_input.dev_attr.attr, /* 41 */
|
||||
&sensor_dev_attr_in12_input.dev_attr.attr, /* 41 */
|
||||
&sensor_dev_attr_in9_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in10_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in11_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in12_input.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
+148
-143
@@ -28,7 +28,6 @@
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
@@ -254,170 +253,148 @@ abort:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* sysfs functions */
|
||||
|
||||
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
static int jc42_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct jc42_data *data = jc42_update_device(dev);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
return sprintf(buf, "%d\n",
|
||||
jc42_temp_from_reg(data->temp[attr->index]));
|
||||
}
|
||||
|
||||
static ssize_t show_temp_hyst(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct jc42_data *data = jc42_update_device(dev);
|
||||
int temp, hyst;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
temp = jc42_temp_from_reg(data->temp[attr->index]);
|
||||
hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
|
||||
>> JC42_CFG_HYST_SHIFT];
|
||||
return sprintf(buf, "%d\n", temp - hyst);
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
*val = jc42_temp_from_reg(data->temp[t_input]);
|
||||
return 0;
|
||||
case hwmon_temp_min:
|
||||
*val = jc42_temp_from_reg(data->temp[t_min]);
|
||||
return 0;
|
||||
case hwmon_temp_max:
|
||||
*val = jc42_temp_from_reg(data->temp[t_max]);
|
||||
return 0;
|
||||
case hwmon_temp_crit:
|
||||
*val = jc42_temp_from_reg(data->temp[t_crit]);
|
||||
return 0;
|
||||
case hwmon_temp_max_hyst:
|
||||
temp = jc42_temp_from_reg(data->temp[t_max]);
|
||||
hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
|
||||
>> JC42_CFG_HYST_SHIFT];
|
||||
*val = temp - hyst;
|
||||
return 0;
|
||||
case hwmon_temp_crit_hyst:
|
||||
temp = jc42_temp_from_reg(data->temp[t_crit]);
|
||||
hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
|
||||
>> JC42_CFG_HYST_SHIFT];
|
||||
*val = temp - hyst;
|
||||
return 0;
|
||||
case hwmon_temp_min_alarm:
|
||||
*val = (data->temp[t_input] >> JC42_ALARM_MIN_BIT) & 1;
|
||||
return 0;
|
||||
case hwmon_temp_max_alarm:
|
||||
*val = (data->temp[t_input] >> JC42_ALARM_MAX_BIT) & 1;
|
||||
return 0;
|
||||
case hwmon_temp_crit_alarm:
|
||||
*val = (data->temp[t_input] >> JC42_ALARM_CRIT_BIT) & 1;
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct jc42_data *data = dev_get_drvdata(dev);
|
||||
int err, ret = count;
|
||||
int nr = attr->index;
|
||||
long val;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
mutex_lock(&data->update_lock);
|
||||
data->temp[nr] = jc42_temp_to_reg(val, data->extended);
|
||||
err = i2c_smbus_write_word_swapped(data->client, temp_regs[nr],
|
||||
data->temp[nr]);
|
||||
if (err < 0)
|
||||
ret = err;
|
||||
mutex_unlock(&data->update_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* JC42.4 compliant chips only support four hysteresis values.
|
||||
* Pick best choice and go from there.
|
||||
*/
|
||||
static ssize_t set_temp_crit_hyst(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static int jc42_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long val)
|
||||
{
|
||||
struct jc42_data *data = dev_get_drvdata(dev);
|
||||
long val;
|
||||
struct i2c_client *client = data->client;
|
||||
int diff, hyst;
|
||||
int err;
|
||||
int ret = count;
|
||||
int ret;
|
||||
|
||||
if (kstrtol(buf, 10, &val) < 0)
|
||||
return -EINVAL;
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
val = clamp_val(val, (data->extended ? JC42_TEMP_MIN_EXTENDED :
|
||||
JC42_TEMP_MIN) - 6000, JC42_TEMP_MAX);
|
||||
diff = jc42_temp_from_reg(data->temp[t_crit]) - val;
|
||||
|
||||
hyst = 0;
|
||||
if (diff > 0) {
|
||||
if (diff < 2250)
|
||||
hyst = 1; /* 1.5 degrees C */
|
||||
else if (diff < 4500)
|
||||
hyst = 2; /* 3.0 degrees C */
|
||||
else
|
||||
hyst = 3; /* 6.0 degrees C */
|
||||
switch (attr) {
|
||||
case hwmon_temp_min:
|
||||
data->temp[t_min] = jc42_temp_to_reg(val, data->extended);
|
||||
ret = i2c_smbus_write_word_swapped(client, temp_regs[t_min],
|
||||
data->temp[t_min]);
|
||||
break;
|
||||
case hwmon_temp_max:
|
||||
data->temp[t_max] = jc42_temp_to_reg(val, data->extended);
|
||||
ret = i2c_smbus_write_word_swapped(client, temp_regs[t_max],
|
||||
data->temp[t_max]);
|
||||
break;
|
||||
case hwmon_temp_crit:
|
||||
data->temp[t_crit] = jc42_temp_to_reg(val, data->extended);
|
||||
ret = i2c_smbus_write_word_swapped(client, temp_regs[t_crit],
|
||||
data->temp[t_crit]);
|
||||
break;
|
||||
case hwmon_temp_crit_hyst:
|
||||
/*
|
||||
* JC42.4 compliant chips only support four hysteresis values.
|
||||
* Pick best choice and go from there.
|
||||
*/
|
||||
val = clamp_val(val, (data->extended ? JC42_TEMP_MIN_EXTENDED
|
||||
: JC42_TEMP_MIN) - 6000,
|
||||
JC42_TEMP_MAX);
|
||||
diff = jc42_temp_from_reg(data->temp[t_crit]) - val;
|
||||
hyst = 0;
|
||||
if (diff > 0) {
|
||||
if (diff < 2250)
|
||||
hyst = 1; /* 1.5 degrees C */
|
||||
else if (diff < 4500)
|
||||
hyst = 2; /* 3.0 degrees C */
|
||||
else
|
||||
hyst = 3; /* 6.0 degrees C */
|
||||
}
|
||||
data->config = (data->config & ~JC42_CFG_HYST_MASK) |
|
||||
(hyst << JC42_CFG_HYST_SHIFT);
|
||||
ret = i2c_smbus_write_word_swapped(data->client,
|
||||
JC42_REG_CONFIG,
|
||||
data->config);
|
||||
break;
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
data->config = (data->config & ~JC42_CFG_HYST_MASK)
|
||||
| (hyst << JC42_CFG_HYST_SHIFT);
|
||||
err = i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
|
||||
data->config);
|
||||
if (err < 0)
|
||||
ret = err;
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t show_alarm(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static umode_t jc42_is_visible(const void *_data, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
u16 bit = to_sensor_dev_attr(attr)->index;
|
||||
struct jc42_data *data = jc42_update_device(dev);
|
||||
u16 val;
|
||||
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
val = data->temp[t_input];
|
||||
if (bit != JC42_ALARM_CRIT_BIT && (data->config & JC42_CFG_CRIT_ONLY))
|
||||
val = 0;
|
||||
return sprintf(buf, "%u\n", (val >> bit) & 1);
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input);
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, set_temp, t_crit);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, set_temp, t_min);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, set_temp, t_max);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_hyst,
|
||||
set_temp_crit_hyst, t_crit);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
|
||||
JC42_ALARM_CRIT_BIT);
|
||||
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
|
||||
JC42_ALARM_MIN_BIT);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
|
||||
JC42_ALARM_MAX_BIT);
|
||||
|
||||
static struct attribute *jc42_attributes[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static umode_t jc42_attribute_mode(struct kobject *kobj,
|
||||
struct attribute *attr, int index)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct jc42_data *data = dev_get_drvdata(dev);
|
||||
const struct jc42_data *data = _data;
|
||||
unsigned int config = data->config;
|
||||
bool readonly;
|
||||
umode_t mode = S_IRUGO;
|
||||
|
||||
if (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr)
|
||||
readonly = config & JC42_CFG_TCRIT_LOCK;
|
||||
else if (attr == &sensor_dev_attr_temp1_min.dev_attr.attr ||
|
||||
attr == &sensor_dev_attr_temp1_max.dev_attr.attr)
|
||||
readonly = config & JC42_CFG_EVENT_LOCK;
|
||||
else if (attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr)
|
||||
readonly = config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK);
|
||||
else
|
||||
readonly = true;
|
||||
|
||||
return S_IRUGO | (readonly ? 0 : S_IWUSR);
|
||||
switch (attr) {
|
||||
case hwmon_temp_min:
|
||||
case hwmon_temp_max:
|
||||
if (!(config & JC42_CFG_EVENT_LOCK))
|
||||
mode |= S_IWUSR;
|
||||
break;
|
||||
case hwmon_temp_crit:
|
||||
if (!(config & JC42_CFG_TCRIT_LOCK))
|
||||
mode |= S_IWUSR;
|
||||
break;
|
||||
case hwmon_temp_crit_hyst:
|
||||
if (!(config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK)))
|
||||
mode |= S_IWUSR;
|
||||
break;
|
||||
case hwmon_temp_input:
|
||||
case hwmon_temp_max_hyst:
|
||||
case hwmon_temp_min_alarm:
|
||||
case hwmon_temp_max_alarm:
|
||||
case hwmon_temp_crit_alarm:
|
||||
break;
|
||||
default:
|
||||
mode = 0;
|
||||
break;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
static const struct attribute_group jc42_group = {
|
||||
.attrs = jc42_attributes,
|
||||
.is_visible = jc42_attribute_mode,
|
||||
};
|
||||
__ATTRIBUTE_GROUPS(jc42);
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info)
|
||||
{
|
||||
@@ -450,6 +427,34 @@ static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static const u32 jc42_temp_config[] = {
|
||||
HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | HWMON_T_CRIT |
|
||||
HWMON_T_MAX_HYST | HWMON_T_CRIT_HYST |
|
||||
HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info jc42_temp = {
|
||||
.type = hwmon_temp,
|
||||
.config = jc42_temp_config,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *jc42_info[] = {
|
||||
&jc42_temp,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_ops jc42_hwmon_ops = {
|
||||
.is_visible = jc42_is_visible,
|
||||
.read = jc42_read,
|
||||
.write = jc42_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info jc42_chip_info = {
|
||||
.ops = &jc42_hwmon_ops,
|
||||
.info = jc42_info,
|
||||
};
|
||||
|
||||
static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
@@ -482,9 +487,9 @@ static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
}
|
||||
data->config = config;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data,
|
||||
jc42_groups);
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
|
||||
data, &jc42_chip_info,
|
||||
NULL);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
|
||||
+118
-71
@@ -28,7 +28,6 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/thermal.h>
|
||||
#include "lm75.h"
|
||||
|
||||
|
||||
@@ -88,56 +87,75 @@ static inline long lm75_reg_to_mc(s16 temp, u8 resolution)
|
||||
return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8);
|
||||
}
|
||||
|
||||
/* sysfs attributes for hwmon */
|
||||
|
||||
static int lm75_read_temp(void *dev, int *temp)
|
||||
static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
struct lm75_data *data = dev_get_drvdata(dev);
|
||||
unsigned int _temp;
|
||||
int err;
|
||||
unsigned int regval;
|
||||
int err, reg;
|
||||
|
||||
err = regmap_read(data->regmap, LM75_REG_TEMP, &_temp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*temp = lm75_reg_to_mc(_temp, data->resolution);
|
||||
switch (type) {
|
||||
case hwmon_chip:
|
||||
switch (attr) {
|
||||
case hwmon_chip_update_interval:
|
||||
*val = data->sample_time;
|
||||
break;;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
reg = LM75_REG_TEMP;
|
||||
break;
|
||||
case hwmon_temp_max:
|
||||
reg = LM75_REG_MAX;
|
||||
break;
|
||||
case hwmon_temp_max_hyst:
|
||||
reg = LM75_REG_HYST;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
err = regmap_read(data->regmap, reg, ®val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*val = lm75_reg_to_mc(regval, data->resolution);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t show_temp(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
static int lm75_write(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long temp)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct lm75_data *data = dev_get_drvdata(dev);
|
||||
unsigned int temp = 0;
|
||||
int err;
|
||||
|
||||
err = regmap_read(data->regmap, attr->index, &temp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return sprintf(buf, "%ld\n", lm75_reg_to_mc(temp, data->resolution));
|
||||
}
|
||||
|
||||
static ssize_t set_temp(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct lm75_data *data = dev_get_drvdata(dev);
|
||||
long temp;
|
||||
int error;
|
||||
u8 resolution;
|
||||
int reg;
|
||||
|
||||
error = kstrtol(buf, 10, &temp);
|
||||
if (error)
|
||||
return error;
|
||||
if (type != hwmon_temp)
|
||||
return -EINVAL;
|
||||
|
||||
switch (attr) {
|
||||
case hwmon_temp_max:
|
||||
reg = LM75_REG_MAX;
|
||||
break;
|
||||
case hwmon_temp_max_hyst:
|
||||
reg = LM75_REG_HYST;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolution of limit registers is assumed to be the same as the
|
||||
* temperature input register resolution unless given explicitly.
|
||||
*/
|
||||
if (attr->index && data->resolution_limits)
|
||||
if (data->resolution_limits)
|
||||
resolution = data->resolution_limits;
|
||||
else
|
||||
resolution = data->resolution;
|
||||
@@ -145,46 +163,78 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
|
||||
temp = clamp_val(temp, LM75_TEMP_MIN, LM75_TEMP_MAX);
|
||||
temp = DIV_ROUND_CLOSEST(temp << (resolution - 8),
|
||||
1000) << (16 - resolution);
|
||||
error = regmap_write(data->regmap, attr->index, temp);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
return count;
|
||||
return regmap_write(data->regmap, reg, temp);
|
||||
}
|
||||
|
||||
static ssize_t show_update_interval(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
struct lm75_data *data = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", data->sample_time);
|
||||
switch (type) {
|
||||
case hwmon_chip:
|
||||
switch (attr) {
|
||||
case hwmon_chip_update_interval:
|
||||
return S_IRUGO;
|
||||
}
|
||||
break;
|
||||
case hwmon_temp:
|
||||
switch (attr) {
|
||||
case hwmon_temp_input:
|
||||
return S_IRUGO;
|
||||
case hwmon_temp_max:
|
||||
case hwmon_temp_max_hyst:
|
||||
return S_IRUGO | S_IWUSR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
|
||||
show_temp, set_temp, LM75_REG_MAX);
|
||||
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
|
||||
show_temp, set_temp, LM75_REG_HYST);
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, LM75_REG_TEMP);
|
||||
static DEVICE_ATTR(update_interval, S_IRUGO, show_update_interval, NULL);
|
||||
|
||||
static struct attribute *lm75_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||
&dev_attr_update_interval.attr,
|
||||
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(lm75);
|
||||
|
||||
static const struct thermal_zone_of_device_ops lm75_of_thermal_ops = {
|
||||
.get_temp = lm75_read_temp,
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/* device probe and removal */
|
||||
|
||||
/* chip configuration */
|
||||
|
||||
static const u32 lm75_chip_config[] = {
|
||||
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info lm75_chip = {
|
||||
.type = hwmon_chip,
|
||||
.config = lm75_chip_config,
|
||||
};
|
||||
|
||||
static const u32 lm75_temp_config[] = {
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info lm75_temp = {
|
||||
.type = hwmon_temp,
|
||||
.config = lm75_temp_config,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *lm75_info[] = {
|
||||
&lm75_chip,
|
||||
&lm75_temp,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_ops lm75_hwmon_ops = {
|
||||
.is_visible = lm75_is_visible,
|
||||
.read = lm75_read,
|
||||
.write = lm75_write,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info lm75_chip_info = {
|
||||
.ops = &lm75_hwmon_ops,
|
||||
.info = lm75_info,
|
||||
};
|
||||
|
||||
static bool lm75_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return reg != LM75_REG_TEMP;
|
||||
@@ -337,15 +387,12 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
|
||||
dev_dbg(dev, "Config %02x\n", new);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
|
||||
data, lm75_groups);
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
|
||||
data, &lm75_chip_info,
|
||||
NULL);
|
||||
if (IS_ERR(hwmon_dev))
|
||||
return PTR_ERR(hwmon_dev);
|
||||
|
||||
devm_thermal_zone_of_sensor_register(hwmon_dev, 0,
|
||||
hwmon_dev,
|
||||
&lm75_of_thermal_ops);
|
||||
|
||||
dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name);
|
||||
|
||||
return 0;
|
||||
|
||||
+522
-463
File diff suppressed because it is too large
Load Diff
+293
-208
File diff suppressed because it is too large
Load Diff
+375
-255
File diff suppressed because it is too large
Load Diff
+20
-2
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -52,6 +53,7 @@ struct ltc4151_data {
|
||||
struct mutex update_lock;
|
||||
bool valid;
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
unsigned int shunt; /* in micro ohms */
|
||||
|
||||
/* Registers */
|
||||
u8 regs[6];
|
||||
@@ -111,9 +113,9 @@ static int ltc4151_get_value(struct ltc4151_data *data, u8 reg)
|
||||
case LTC4151_SENSE_H:
|
||||
/*
|
||||
* 20uV resolution. Convert to current as measured with
|
||||
* an 1 mOhm sense resistor, in mA.
|
||||
* a given sense resistor, in mA.
|
||||
*/
|
||||
val = val * 20;
|
||||
val = val * 20 * 1000 / data->shunt;
|
||||
break;
|
||||
case LTC4151_VIN_H:
|
||||
/* 25 mV per increment */
|
||||
@@ -176,6 +178,7 @@ static int ltc4151_probe(struct i2c_client *client,
|
||||
struct device *dev = &client->dev;
|
||||
struct ltc4151_data *data;
|
||||
struct device *hwmon_dev;
|
||||
u32 shunt;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
@@ -184,6 +187,15 @@ static int ltc4151_probe(struct i2c_client *client,
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_u32(client->dev.of_node,
|
||||
"shunt-resistor-micro-ohms", &shunt))
|
||||
shunt = 1000; /* 1 mOhm if not set via DT */
|
||||
|
||||
if (shunt == 0)
|
||||
return -EINVAL;
|
||||
|
||||
data->shunt = shunt;
|
||||
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
@@ -199,10 +211,16 @@ static const struct i2c_device_id ltc4151_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc4151_id);
|
||||
|
||||
static const struct of_device_id ltc4151_match[] = {
|
||||
{ .compatible = "lltc,ltc4151" },
|
||||
{},
|
||||
};
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver ltc4151_driver = {
|
||||
.driver = {
|
||||
.name = "ltc4151",
|
||||
.of_match_table = of_match_ptr(ltc4151_match),
|
||||
},
|
||||
.probe = ltc4151_probe,
|
||||
.id_table = ltc4151_id,
|
||||
|
||||
+190
-202
@@ -16,6 +16,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -53,8 +54,6 @@ enum ltc4245_cmd {
|
||||
struct ltc4245_data {
|
||||
struct i2c_client *client;
|
||||
|
||||
const struct attribute_group *groups[3];
|
||||
|
||||
struct mutex update_lock;
|
||||
bool valid;
|
||||
unsigned long last_updated; /* in jiffies */
|
||||
@@ -162,7 +161,7 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
|
||||
ltc4245_update_gpios(dev);
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
data->valid = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
@@ -256,214 +255,205 @@ static unsigned int ltc4245_get_current(struct device *dev, u8 reg)
|
||||
return curr;
|
||||
}
|
||||
|
||||
static ssize_t ltc4245_show_voltage(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
/* Map from voltage channel index to voltage register */
|
||||
|
||||
static const s8 ltc4245_in_regs[] = {
|
||||
LTC4245_12VIN, LTC4245_5VIN, LTC4245_3VIN, LTC4245_VEEIN,
|
||||
LTC4245_12VOUT, LTC4245_5VOUT, LTC4245_3VOUT, LTC4245_VEEOUT,
|
||||
};
|
||||
|
||||
/* Map from current channel index to current register */
|
||||
|
||||
static const s8 ltc4245_curr_regs[] = {
|
||||
LTC4245_12VSENSE, LTC4245_5VSENSE, LTC4245_3VSENSE, LTC4245_VEESENSE,
|
||||
};
|
||||
|
||||
static int ltc4245_read_curr(struct device *dev, u32 attr, int channel,
|
||||
long *val)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
const int voltage = ltc4245_get_voltage(dev, attr->index);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", voltage);
|
||||
}
|
||||
|
||||
static ssize_t ltc4245_show_current(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
const unsigned int curr = ltc4245_get_current(dev, attr->index);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", curr);
|
||||
}
|
||||
|
||||
static ssize_t ltc4245_show_power(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
const unsigned int curr = ltc4245_get_current(dev, attr->index);
|
||||
const int output_voltage = ltc4245_get_voltage(dev, attr->index+1);
|
||||
|
||||
/* current in mA * voltage in mV == power in uW */
|
||||
const unsigned int power = abs(output_voltage * curr);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", power);
|
||||
}
|
||||
|
||||
static ssize_t ltc4245_show_alarm(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da);
|
||||
struct ltc4245_data *data = ltc4245_update_device(dev);
|
||||
const u8 reg = data->cregs[attr->index];
|
||||
const u32 mask = attr->nr;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
|
||||
switch (attr) {
|
||||
case hwmon_curr_input:
|
||||
*val = ltc4245_get_current(dev, ltc4245_curr_regs[channel]);
|
||||
return 0;
|
||||
case hwmon_curr_max_alarm:
|
||||
*val = !!(data->cregs[LTC4245_FAULT1] & BIT(channel + 4));
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t ltc4245_show_gpio(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
char *buf)
|
||||
static int ltc4245_read_in(struct device *dev, u32 attr, int channel, long *val)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct ltc4245_data *data = ltc4245_update_device(dev);
|
||||
int val = data->gpios[attr->index];
|
||||
|
||||
/* handle stale GPIO's */
|
||||
if (val < 0)
|
||||
return val;
|
||||
switch (attr) {
|
||||
case hwmon_in_input:
|
||||
if (channel < 8) {
|
||||
*val = ltc4245_get_voltage(dev,
|
||||
ltc4245_in_regs[channel]);
|
||||
} else {
|
||||
int regval = data->gpios[channel - 8];
|
||||
|
||||
/* Convert to millivolts and print */
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", val * 10);
|
||||
if (regval < 0)
|
||||
return regval;
|
||||
*val = regval * 10;
|
||||
}
|
||||
return 0;
|
||||
case hwmon_in_min_alarm:
|
||||
if (channel < 4)
|
||||
*val = !!(data->cregs[LTC4245_FAULT1] & BIT(channel));
|
||||
else
|
||||
*val = !!(data->cregs[LTC4245_FAULT2] &
|
||||
BIT(channel - 4));
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
/* Construct a sensor_device_attribute structure for each register */
|
||||
|
||||
/* Input voltages */
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_12VIN);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_5VIN);
|
||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_3VIN);
|
||||
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_VEEIN);
|
||||
|
||||
/* Input undervoltage alarms */
|
||||
static SENSOR_DEVICE_ATTR_2(in1_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 0, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(in2_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 1, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(in3_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 2, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(in4_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 3, LTC4245_FAULT1);
|
||||
|
||||
/* Currents (via sense resistor) */
|
||||
static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ltc4245_show_current, NULL,
|
||||
LTC4245_12VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, ltc4245_show_current, NULL,
|
||||
LTC4245_5VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(curr3_input, S_IRUGO, ltc4245_show_current, NULL,
|
||||
LTC4245_3VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(curr4_input, S_IRUGO, ltc4245_show_current, NULL,
|
||||
LTC4245_VEESENSE);
|
||||
|
||||
/* Overcurrent alarms */
|
||||
static SENSOR_DEVICE_ATTR_2(curr1_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 4, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(curr2_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 5, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(curr3_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 6, LTC4245_FAULT1);
|
||||
static SENSOR_DEVICE_ATTR_2(curr4_max_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 7, LTC4245_FAULT1);
|
||||
|
||||
/* Output voltages */
|
||||
static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_12VOUT);
|
||||
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_5VOUT);
|
||||
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_3VOUT);
|
||||
static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, ltc4245_show_voltage, NULL,
|
||||
LTC4245_VEEOUT);
|
||||
|
||||
/* Power Bad alarms */
|
||||
static SENSOR_DEVICE_ATTR_2(in5_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 0, LTC4245_FAULT2);
|
||||
static SENSOR_DEVICE_ATTR_2(in6_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 1, LTC4245_FAULT2);
|
||||
static SENSOR_DEVICE_ATTR_2(in7_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 2, LTC4245_FAULT2);
|
||||
static SENSOR_DEVICE_ATTR_2(in8_min_alarm, S_IRUGO, ltc4245_show_alarm, NULL,
|
||||
1 << 3, LTC4245_FAULT2);
|
||||
|
||||
/* GPIO voltages */
|
||||
static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, ltc4245_show_gpio, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, ltc4245_show_gpio, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, ltc4245_show_gpio, NULL, 2);
|
||||
|
||||
/* Power Consumption (virtual) */
|
||||
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ltc4245_show_power, NULL,
|
||||
LTC4245_12VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, ltc4245_show_power, NULL,
|
||||
LTC4245_5VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(power3_input, S_IRUGO, ltc4245_show_power, NULL,
|
||||
LTC4245_3VSENSE);
|
||||
static SENSOR_DEVICE_ATTR(power4_input, S_IRUGO, ltc4245_show_power, NULL,
|
||||
LTC4245_VEESENSE);
|
||||
|
||||
/*
|
||||
* Finally, construct an array of pointers to members of the above objects,
|
||||
* as required for sysfs_create_group()
|
||||
*/
|
||||
static struct attribute *ltc4245_std_attributes[] = {
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_input.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in4_min_alarm.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_curr1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_curr2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_curr3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_curr4_input.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_curr2_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_curr3_max_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_curr4_max_alarm.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_in5_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_input.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_in5_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in6_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in7_min_alarm.dev_attr.attr,
|
||||
&sensor_dev_attr_in8_min_alarm.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_in9_input.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_power1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_power2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_power3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_power4_input.dev_attr.attr,
|
||||
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute *ltc4245_gpio_attributes[] = {
|
||||
&sensor_dev_attr_in10_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in11_input.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ltc4245_std_group = {
|
||||
.attrs = ltc4245_std_attributes,
|
||||
};
|
||||
|
||||
static const struct attribute_group ltc4245_gpio_group = {
|
||||
.attrs = ltc4245_gpio_attributes,
|
||||
};
|
||||
|
||||
static void ltc4245_sysfs_add_groups(struct ltc4245_data *data)
|
||||
static int ltc4245_read_power(struct device *dev, u32 attr, int channel,
|
||||
long *val)
|
||||
{
|
||||
/* standard sysfs attributes */
|
||||
data->groups[0] = <c4245_std_group;
|
||||
unsigned long curr;
|
||||
long voltage;
|
||||
|
||||
/* if we're using the extra gpio support, register it's attributes */
|
||||
if (data->use_extra_gpios)
|
||||
data->groups[1] = <c4245_gpio_group;
|
||||
switch (attr) {
|
||||
case hwmon_power_input:
|
||||
(void)ltc4245_update_device(dev);
|
||||
curr = ltc4245_get_current(dev, ltc4245_curr_regs[channel]);
|
||||
voltage = ltc4245_get_voltage(dev, ltc4245_in_regs[channel]);
|
||||
*val = abs(curr * voltage);
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int ltc4245_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case hwmon_curr:
|
||||
return ltc4245_read_curr(dev, attr, channel, val);
|
||||
case hwmon_power:
|
||||
return ltc4245_read_power(dev, attr, channel, val);
|
||||
case hwmon_in:
|
||||
return ltc4245_read_in(dev, attr, channel - 1, val);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static umode_t ltc4245_is_visible(const void *_data,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
const struct ltc4245_data *data = _data;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_in:
|
||||
if (channel == 0)
|
||||
return 0;
|
||||
switch (attr) {
|
||||
case hwmon_in_input:
|
||||
if (channel > 9 && !data->use_extra_gpios)
|
||||
return 0;
|
||||
return S_IRUGO;
|
||||
case hwmon_in_min_alarm:
|
||||
if (channel > 8)
|
||||
return 0;
|
||||
return S_IRUGO;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case hwmon_curr:
|
||||
switch (attr) {
|
||||
case hwmon_curr_input:
|
||||
case hwmon_curr_max_alarm:
|
||||
return S_IRUGO;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case hwmon_power:
|
||||
switch (attr) {
|
||||
case hwmon_power_input:
|
||||
return S_IRUGO;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const u32 ltc4245_in_config[] = {
|
||||
HWMON_I_INPUT, /* dummy, skipped in is_visible */
|
||||
HWMON_I_INPUT | HWMON_I_MIN_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN_ALARM,
|
||||
HWMON_I_INPUT | HWMON_I_MIN_ALARM,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
HWMON_I_INPUT,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info ltc4245_in = {
|
||||
.type = hwmon_in,
|
||||
.config = ltc4245_in_config,
|
||||
};
|
||||
|
||||
static const u32 ltc4245_curr_config[] = {
|
||||
HWMON_C_INPUT | HWMON_C_MAX_ALARM,
|
||||
HWMON_C_INPUT | HWMON_C_MAX_ALARM,
|
||||
HWMON_C_INPUT | HWMON_C_MAX_ALARM,
|
||||
HWMON_C_INPUT | HWMON_C_MAX_ALARM,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info ltc4245_curr = {
|
||||
.type = hwmon_curr,
|
||||
.config = ltc4245_curr_config,
|
||||
};
|
||||
|
||||
static const u32 ltc4245_power_config[] = {
|
||||
HWMON_P_INPUT,
|
||||
HWMON_P_INPUT,
|
||||
HWMON_P_INPUT,
|
||||
HWMON_P_INPUT,
|
||||
0
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info ltc4245_power = {
|
||||
.type = hwmon_power,
|
||||
.config = ltc4245_power_config,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info *ltc4245_info[] = {
|
||||
<c4245_in,
|
||||
<c4245_curr,
|
||||
<c4245_power,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_ops ltc4245_hwmon_ops = {
|
||||
.is_visible = ltc4245_is_visible,
|
||||
.read = ltc4245_read,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info ltc4245_chip_info = {
|
||||
.ops = <c4245_hwmon_ops,
|
||||
.info = ltc4245_info,
|
||||
};
|
||||
|
||||
static bool ltc4245_use_extra_gpios(struct i2c_client *client)
|
||||
{
|
||||
struct ltc4245_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
@@ -502,12 +492,10 @@ static int ltc4245_probe(struct i2c_client *client,
|
||||
i2c_smbus_write_byte_data(client, LTC4245_FAULT1, 0x00);
|
||||
i2c_smbus_write_byte_data(client, LTC4245_FAULT2, 0x00);
|
||||
|
||||
/* Add sysfs hooks */
|
||||
ltc4245_sysfs_add_groups(data);
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev,
|
||||
client->name, data,
|
||||
data->groups);
|
||||
hwmon_dev = devm_hwmon_device_register_with_info(&client->dev,
|
||||
client->name, data,
|
||||
<c4245_chip_info,
|
||||
NULL);
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
|
||||
+233
-306
File diff suppressed because it is too large
Load Diff
+103
-52
@@ -39,6 +39,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
/*
|
||||
* Insmod parameters
|
||||
@@ -48,7 +49,7 @@
|
||||
static int fan_voltage;
|
||||
/* prescaler: Possible values are 1, 2, 4, 8, 16 or 0 for don't change */
|
||||
static int prescaler;
|
||||
/* clock: The clock frequency of the chip the driver should assume */
|
||||
/* clock: The clock frequency of the chip (max6651 can be clocked externally) */
|
||||
static int clock = 254000;
|
||||
|
||||
module_param(fan_voltage, int, S_IRUGO);
|
||||
@@ -133,6 +134,19 @@ static const u8 tach_reg[] = {
|
||||
MAX6650_REG_TACH3,
|
||||
};
|
||||
|
||||
static const struct of_device_id max6650_dt_match[] = {
|
||||
{
|
||||
.compatible = "maxim,max6650",
|
||||
.data = (void *)1
|
||||
},
|
||||
{
|
||||
.compatible = "maxim,max6651",
|
||||
.data = (void *)4
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max6650_dt_match);
|
||||
|
||||
static struct max6650_data *max6650_update_device(struct device *dev)
|
||||
{
|
||||
struct max6650_data *data = dev_get_drvdata(dev);
|
||||
@@ -171,6 +185,30 @@ static struct max6650_data *max6650_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the operating mode of the chip (if needed).
|
||||
* mode is one of the MAX6650_CFG_MODE_* values.
|
||||
*/
|
||||
static int max6650_set_operating_mode(struct max6650_data *data, u8 mode)
|
||||
{
|
||||
int result;
|
||||
u8 config = data->config;
|
||||
|
||||
if (mode == (config & MAX6650_CFG_MODE_MASK))
|
||||
return 0;
|
||||
|
||||
config = (config & ~MAX6650_CFG_MODE_MASK) | mode;
|
||||
|
||||
result = i2c_smbus_write_byte_data(data->client, MAX6650_REG_CONFIG,
|
||||
config);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
data->config = config;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t get_fan(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
@@ -252,18 +290,12 @@ static ssize_t get_target(struct device *dev, struct device_attribute *devattr,
|
||||
return sprintf(buf, "%d\n", rpm);
|
||||
}
|
||||
|
||||
static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
static int max6650_set_target(struct max6650_data *data, unsigned long rpm)
|
||||
{
|
||||
struct max6650_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int kscale, ktach;
|
||||
unsigned long rpm;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &rpm);
|
||||
if (err)
|
||||
return err;
|
||||
if (rpm == 0)
|
||||
return max6650_set_operating_mode(data, MAX6650_CFG_MODE_OFF);
|
||||
|
||||
rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
|
||||
|
||||
@@ -274,8 +306,6 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
|
||||
* KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1
|
||||
*/
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
kscale = DIV_FROM_REG(data->config);
|
||||
ktach = ((clock * kscale) / (256 * rpm / 60)) - 1;
|
||||
if (ktach < 0)
|
||||
@@ -284,10 +314,30 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
|
||||
ktach = 255;
|
||||
data->speed = ktach;
|
||||
|
||||
i2c_smbus_write_byte_data(client, MAX6650_REG_SPEED, data->speed);
|
||||
return i2c_smbus_write_byte_data(data->client, MAX6650_REG_SPEED,
|
||||
data->speed);
|
||||
}
|
||||
|
||||
static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct max6650_data *data = dev_get_drvdata(dev);
|
||||
unsigned long rpm;
|
||||
int err;
|
||||
|
||||
err = kstrtoul(buf, 10, &rpm);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
err = max6650_set_target(data, rpm);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -341,12 +391,11 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
|
||||
data->dac = 180 - (180 * pwm)/255;
|
||||
else
|
||||
data->dac = 76 - (76 * pwm)/255;
|
||||
|
||||
i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
|
||||
err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return count;
|
||||
return err < 0 ? err : count;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -355,14 +404,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
|
||||
* 0 = Fan always on
|
||||
* 1 = Open loop, Voltage is set according to speed, not regulated.
|
||||
* 2 = Closed loop, RPM for all fans regulated by fan1 tachometer
|
||||
* 3 = Fan off
|
||||
*/
|
||||
|
||||
static ssize_t get_enable(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct max6650_data *data = max6650_update_device(dev);
|
||||
int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
|
||||
int sysfs_modes[4] = {0, 1, 2, 1};
|
||||
int sysfs_modes[4] = {0, 3, 2, 1};
|
||||
|
||||
return sprintf(buf, "%d\n", sysfs_modes[mode]);
|
||||
}
|
||||
@@ -371,25 +420,25 @@ static ssize_t set_enable(struct device *dev, struct device_attribute *devattr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct max6650_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int max6650_modes[3] = {0, 3, 2};
|
||||
unsigned long mode;
|
||||
int err;
|
||||
const u8 max6650_modes[] = {
|
||||
MAX6650_CFG_MODE_ON,
|
||||
MAX6650_CFG_MODE_OPEN_LOOP,
|
||||
MAX6650_CFG_MODE_CLOSED_LOOP,
|
||||
MAX6650_CFG_MODE_OFF,
|
||||
};
|
||||
|
||||
err = kstrtoul(buf, 10, &mode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (mode > 2)
|
||||
if (mode >= ARRAY_SIZE(max6650_modes))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
data->config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
|
||||
data->config = (data->config & ~MAX6650_CFG_MODE_MASK)
|
||||
| (max6650_modes[mode] << 4);
|
||||
|
||||
i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, data->config);
|
||||
max6650_set_operating_mode(data, max6650_modes[mode]);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
@@ -566,6 +615,18 @@ static int max6650_init_client(struct max6650_data *data,
|
||||
struct device *dev = &client->dev;
|
||||
int config;
|
||||
int err = -EIO;
|
||||
u32 voltage;
|
||||
u32 prescale;
|
||||
u32 target_rpm;
|
||||
|
||||
if (of_property_read_u32(dev->of_node, "maxim,fan-microvolt",
|
||||
&voltage))
|
||||
voltage = fan_voltage;
|
||||
else
|
||||
voltage /= 1000000; /* Microvolts to volts */
|
||||
if (of_property_read_u32(dev->of_node, "maxim,fan-prescale",
|
||||
&prescale))
|
||||
prescale = prescaler;
|
||||
|
||||
config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
|
||||
|
||||
@@ -574,7 +635,7 @@ static int max6650_init_client(struct max6650_data *data,
|
||||
return err;
|
||||
}
|
||||
|
||||
switch (fan_voltage) {
|
||||
switch (voltage) {
|
||||
case 0:
|
||||
break;
|
||||
case 5:
|
||||
@@ -584,14 +645,10 @@ static int max6650_init_client(struct max6650_data *data,
|
||||
config |= MAX6650_CFG_V12;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "illegal value for fan_voltage (%d)\n",
|
||||
fan_voltage);
|
||||
dev_err(dev, "illegal value for fan_voltage (%d)\n", voltage);
|
||||
}
|
||||
|
||||
dev_info(dev, "Fan voltage is set to %dV.\n",
|
||||
(config & MAX6650_CFG_V12) ? 12 : 5);
|
||||
|
||||
switch (prescaler) {
|
||||
switch (prescale) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
@@ -614,28 +671,13 @@ static int max6650_init_client(struct max6650_data *data,
|
||||
| MAX6650_CFG_PRESCALER_16;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "illegal value for prescaler (%d)\n", prescaler);
|
||||
dev_err(dev, "illegal value for prescaler (%d)\n", prescale);
|
||||
}
|
||||
|
||||
dev_info(dev, "Prescaler is set to %d.\n",
|
||||
dev_info(dev, "Fan voltage: %dV, prescaler: %d.\n",
|
||||
(config & MAX6650_CFG_V12) ? 12 : 5,
|
||||
1 << (config & MAX6650_CFG_PRESCALER_MASK));
|
||||
|
||||
/*
|
||||
* If mode is set to "full off", we change it to "open loop" and
|
||||
* set DAC to 255, which has the same effect. We do this because
|
||||
* there's no "full off" mode defined in hwmon specifications.
|
||||
*/
|
||||
|
||||
if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) {
|
||||
dev_dbg(dev, "Change mode to open loop, full off.\n");
|
||||
config = (config & ~MAX6650_CFG_MODE_MASK)
|
||||
| MAX6650_CFG_MODE_OPEN_LOOP;
|
||||
if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) {
|
||||
dev_err(dev, "DAC write error, aborting.\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
|
||||
dev_err(dev, "Config write error, aborting.\n");
|
||||
return err;
|
||||
@@ -644,6 +686,12 @@ static int max6650_init_client(struct max6650_data *data,
|
||||
data->config = config;
|
||||
data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
|
||||
|
||||
if (!of_property_read_u32(client->dev.of_node, "maxim,fan-target-rpm",
|
||||
&target_rpm)) {
|
||||
max6650_set_target(data, target_rpm);
|
||||
max6650_set_operating_mode(data, MAX6650_CFG_MODE_CLOSED_LOOP);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -651,6 +699,8 @@ static int max6650_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(of_match_ptr(max6650_dt_match), dev);
|
||||
struct max6650_data *data;
|
||||
struct device *hwmon_dev;
|
||||
int err;
|
||||
@@ -661,7 +711,7 @@ static int max6650_probe(struct i2c_client *client,
|
||||
|
||||
data->client = client;
|
||||
mutex_init(&data->update_lock);
|
||||
data->nr_fans = id->driver_data;
|
||||
data->nr_fans = of_id ? (int)(uintptr_t)of_id->data : id->driver_data;
|
||||
|
||||
/*
|
||||
* Initialize the max6650 chip
|
||||
@@ -691,6 +741,7 @@ MODULE_DEVICE_TABLE(i2c, max6650_id);
|
||||
static struct i2c_driver max6650_driver = {
|
||||
.driver = {
|
||||
.name = "max6650",
|
||||
.of_match_table = of_match_ptr(max6650_dt_match),
|
||||
},
|
||||
.probe = max6650_probe,
|
||||
.id_table = max6650_id,
|
||||
|
||||
+17
-6
@@ -195,6 +195,8 @@ superio_exit(int ioreg)
|
||||
|
||||
#define NUM_FAN 6
|
||||
|
||||
#define TEMP_SOURCE_VIRTUAL 0x1f
|
||||
|
||||
/* Common and NCT6775 specific data */
|
||||
|
||||
/* Voltage min/max registers for nr=7..14 are in bank 5 */
|
||||
@@ -3940,7 +3942,7 @@ static int nct6775_probe(struct platform_device *pdev)
|
||||
continue;
|
||||
|
||||
src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f;
|
||||
if (!src || (mask & (1 << src)))
|
||||
if (!src)
|
||||
continue;
|
||||
|
||||
if (src >= data->temp_label_num ||
|
||||
@@ -3952,7 +3954,16 @@ static int nct6775_probe(struct platform_device *pdev)
|
||||
continue;
|
||||
}
|
||||
|
||||
mask |= 1 << src;
|
||||
/*
|
||||
* For virtual temperature sources, the 'virtual' temperature
|
||||
* for each fan reflects a different temperature, and there
|
||||
* are no duplicates.
|
||||
*/
|
||||
if (src != TEMP_SOURCE_VIRTUAL) {
|
||||
if (mask & (1 << src))
|
||||
continue;
|
||||
mask |= 1 << src;
|
||||
}
|
||||
|
||||
/* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
|
||||
if (src <= data->temp_fixed_num) {
|
||||
@@ -4232,11 +4243,11 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (force_id)
|
||||
val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) |
|
||||
superio_inb(sioaddr, SIO_REG_DEVID + 1);
|
||||
if (force_id && val != 0xffff)
|
||||
val = force_id;
|
||||
else
|
||||
val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
|
||||
| superio_inb(sioaddr, SIO_REG_DEVID + 1);
|
||||
|
||||
switch (val & SIO_ID_MASK) {
|
||||
case SIO_NCT6106_ID:
|
||||
sio_data->kind = nct6106;
|
||||
|
||||
+270
-285
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user