hwmon updates for v4.15

- Drivers for MAX31785 and MAX6621
 - Support for AMD family 17h (Ryzen, Threadripper) temperature sensors
 - Various driver cleanups and minor improvements
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJaCKuYAAoJEMsfJm/On5mBjVAP/A/gfAv5KGYsuzEm+Oph3UFq
 dQsuqEr7cUhBnhApwfotT9ygNWRfVknPyvCjTJanHXca1eAE+4srgXY3yRpo5s6R
 YlVbkT7fYRO+SrjXsWhKBcctzKjrkyiNYTz+BqGbzQ9Y6QStnkrQTweB1NOAkasy
 o7WsAlh9bX4966GyAq6OOQZ3dOwvKGVl8dovEJQk5ZtW0e0TOrGbPM5KZsXN+Haa
 adUAMBhxEzSH7SqO1UIlnn0DfF7Ikp291Vy03LZKnGDIN/myI602HrRerrnZhDw6
 Beq4YyYRjNVqwkkIwpAlElKAGK5QXhbuUb9ScvhEMZSf2e80t/NzLmDQrWVKevAy
 VSnFaP+cKIx9hYMwQe92fbn1dhASOf5z+LxzC8kyAloUHZ8ZGH6JEkPRFPCijoiV
 MQ+/YM1jpzzAqiW1HilxVouVjq0lhJwrnqozwbrF/HfyeIzBVd76o+4AIrOVFKLR
 zXtKbiLsFQz3GDRGzCp5CswQnyFMU0K5Hpx2iSd7UYx6OWH6Q5Hf6ieC8LJmst1d
 akbFSiExgF+CIZc5TYaFIBO740vpo8EXJesGIA6uZYoMxk8iConahMAkzJV5ik3Z
 H1LghVhkgYjccdJQ/dxfmQ87+P4bYeRp0KQPRHBAHTcUe0htqR006rcsDDBwznGx
 LwrUeeSMf+dS7dj+jSLV
 =NpxT
 -----END PGP SIGNATURE-----

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

Pull hwmon updates from Guenter Roeck:

 - drivers for MAX31785 and MAX6621

 - support for AMD family 17h (Ryzen, Threadripper) temperature sensors

 - various driver cleanups and minor improvements

* tag 'hwmon-for-linus-v4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (30 commits)
  dt-bindings: pmbus: Add Maxim MAX31785 documentation
  pmbus: Add driver for Maxim MAX31785 Intelligent Fan Controller
  hwmon: (aspeed-pwm-tacho) Sort headers
  hwmon: (xgene) Minor clean up of ifdef and acpi_match_table reference
  hwmon: (max6621) Inverted if condition in max6621_read()
  hwmon: (asc7621) remove redundant assignment to newval
  hwmon: (xgene) Support hwmon v2
  hwmon: (gpio-fan) Fix null pointer dereference at probe
  hwmon: (gpio-fan) Convert to use GPIO descriptors
  hwmon: (gpio-fan) Rename GPIO line state variables
  hwmon: (gpio-fan) Get rid of the gpio alarm struct
  hwmon: (gpio-fan) Get rid of platform data struct
  hwmon: (gpio-fan) Mandate OF_GPIO and cut pdata path
  hwmon: (gpio-fan) Send around device pointer
  hwmon: (gpio-fan) Localize platform data
  hwmon: (gpio-fan) Use local variable pointers
  hwmon: (gpio-fan) Move DT bindings to the right place
  Documentation: devicetree: add max6621 device
  hwmon: (max6621) Add support for Maxim MAX6621 temperature sensor
  hwmon: (w83793) make const array watchdog_minors static, reduces object code size
  ...
This commit is contained in:
Linus Torvalds 2017-11-13 08:55:46 -08:00
commit 1e19bded7f
26 changed files with 1131 additions and 403 deletions

View file

@ -552,6 +552,7 @@ config SENSORS_G762
config SENSORS_GPIO_FAN
tristate "GPIO fan"
depends on OF_GPIO
depends on GPIOLIB || COMPILE_TEST
depends on THERMAL || THERMAL=n
help
@ -862,6 +863,20 @@ tristate "MAX31722 temperature sensor"
This driver can also be built as a module. If so, the module
will be called max31722.
config SENSORS_MAX6621
tristate "Maxim MAX6621 sensor chip"
depends on I2C
select REGMAP_I2C
help
If you say yes here you get support for MAX6621 sensor chip.
MAX6621 is a PECI-to-I2C translator provides an efficient,
low-cost solution for PECI-to-SMBus/I2C protocol conversion.
It allows reading the temperature from the PECI-compliant
host directly from up to four PECI-enabled CPUs.
This driver can also be built as a module. If so, the module
will be called max6621.
config SENSORS_MAX6639
tristate "Maxim MAX6639 sensor chip"
depends on I2C

View file

@ -118,6 +118,7 @@ obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX1668) += max1668.o
obj-$(CONFIG_SENSORS_MAX197) += max197.o
obj-$(CONFIG_SENSORS_MAX31722) += max31722.o
obj-$(CONFIG_SENSORS_MAX6621) += max6621.o
obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o

View file

@ -579,7 +579,6 @@ static ssize_t show_pwm_enable(struct device *dev,
mutex_unlock(&data->update_lock);
val = config | (altbit << 3);
newval = 0;
if (val == 3 || val >= 10)
newval = 255;

View file

@ -7,19 +7,19 @@
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/sysfs.h>
#include <linux/regmap.h>
#include <linux/sysfs.h>
#include <linux/thermal.h>
/* ASPEED PWM & FAN Tach Register Definition */
@ -161,7 +161,7 @@
* 11: reserved.
*/
#define M_TACH_MODE 0x02 /* 10b */
#define M_TACH_UNIT 0x00c0
#define M_TACH_UNIT 0x0210
#define INIT_FAN_CTRL 0xFF
/* How long we sleep in us while waiting for an RPM result. */

View file

@ -29,21 +29,24 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/hwmon.h>
#include <linux/gpio.h>
#include <linux/gpio-fan.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/thermal.h>
struct gpio_fan_speed {
int rpm;
int ctrl_val;
};
struct gpio_fan_data {
struct platform_device *pdev;
struct device *dev;
struct device *hwmon_dev;
/* Cooling device if any */
struct thermal_cooling_device *cdev;
struct mutex lock; /* lock GPIOs operations. */
int num_ctrl;
unsigned *ctrl;
int num_gpios;
struct gpio_desc **gpios;
int num_speed;
struct gpio_fan_speed *speed;
int speed_index;
@ -51,7 +54,7 @@ struct gpio_fan_data {
int resume_speed;
#endif
bool pwm_enable;
struct gpio_fan_alarm *alarm;
struct gpio_desc *alarm_gpio;
struct work_struct alarm_work;
};
@ -64,8 +67,8 @@ static void fan_alarm_notify(struct work_struct *ws)
struct gpio_fan_data *fan_data =
container_of(ws, struct gpio_fan_data, alarm_work);
sysfs_notify(&fan_data->pdev->dev.kobj, NULL, "fan1_alarm");
kobject_uevent(&fan_data->pdev->dev.kobj, KOBJ_CHANGE);
sysfs_notify(&fan_data->dev->kobj, NULL, "fan1_alarm");
kobject_uevent(&fan_data->dev->kobj, KOBJ_CHANGE);
}
static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id)
@ -81,47 +84,30 @@ static ssize_t fan1_alarm_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
struct gpio_fan_alarm *alarm = fan_data->alarm;
int value = gpio_get_value_cansleep(alarm->gpio);
if (alarm->active_low)
value = !value;
return sprintf(buf, "%d\n", value);
return sprintf(buf, "%d\n",
gpiod_get_value_cansleep(fan_data->alarm_gpio));
}
static DEVICE_ATTR_RO(fan1_alarm);
static int fan_alarm_init(struct gpio_fan_data *fan_data,
struct gpio_fan_alarm *alarm)
static int fan_alarm_init(struct gpio_fan_data *fan_data)
{
int err;
int alarm_irq;
struct platform_device *pdev = fan_data->pdev;
fan_data->alarm = alarm;
err = devm_gpio_request(&pdev->dev, alarm->gpio, "GPIO fan alarm");
if (err)
return err;
err = gpio_direction_input(alarm->gpio);
if (err)
return err;
struct device *dev = fan_data->dev;
/*
* If the alarm GPIO don't support interrupts, just leave
* without initializing the fail notification support.
*/
alarm_irq = gpio_to_irq(alarm->gpio);
if (alarm_irq < 0)
alarm_irq = gpiod_to_irq(fan_data->alarm_gpio);
if (alarm_irq <= 0)
return 0;
INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
err = devm_request_irq(&pdev->dev, alarm_irq, fan_alarm_irq_handler,
IRQF_SHARED, "GPIO fan alarm", fan_data);
return err;
return devm_request_irq(dev, alarm_irq, fan_alarm_irq_handler,
IRQF_SHARED, "GPIO fan alarm", fan_data);
}
/*
@ -133,8 +119,9 @@ 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_cansleep(fan_data->ctrl[i], (ctrl_val >> i) & 1);
for (i = 0; i < fan_data->num_gpios; i++)
gpiod_set_value_cansleep(fan_data->gpios[i],
(ctrl_val >> i) & 1);
}
static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
@ -142,10 +129,10 @@ static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
int i;
int ctrl_val = 0;
for (i = 0; i < fan_data->num_ctrl; i++) {
for (i = 0; i < fan_data->num_gpios; i++) {
int value;
value = gpio_get_value_cansleep(fan_data->ctrl[i]);
value = gpiod_get_value_cansleep(fan_data->gpios[i]);
ctrl_val |= (value << i);
}
return ctrl_val;
@ -170,7 +157,7 @@ static int get_fan_speed_index(struct gpio_fan_data *fan_data)
if (fan_data->speed[i].ctrl_val == ctrl_val)
return i;
dev_warn(&fan_data->pdev->dev,
dev_warn(fan_data->dev,
"missing speed array entry for GPIO value 0x%x\n", ctrl_val);
return -ENODEV;
@ -328,9 +315,9 @@ static umode_t gpio_fan_is_visible(struct kobject *kobj,
struct device *dev = container_of(kobj, struct device, kobj);
struct gpio_fan_data *data = dev_get_drvdata(dev);
if (index == 0 && !data->alarm)
if (index == 0 && !data->alarm_gpio)
return 0;
if (index > 0 && !data->ctrl)
if (index > 0 && !data->gpios)
return 0;
return attr->mode;
@ -358,30 +345,25 @@ static const struct attribute_group *gpio_fan_groups[] = {
NULL
};
static int fan_ctrl_init(struct gpio_fan_data *fan_data,
struct gpio_fan_platform_data *pdata)
static int fan_ctrl_init(struct gpio_fan_data *fan_data)
{
struct platform_device *pdev = fan_data->pdev;
int num_ctrl = pdata->num_ctrl;
unsigned *ctrl = pdata->ctrl;
int num_gpios = fan_data->num_gpios;
struct gpio_desc **gpios = fan_data->gpios;
int i, err;
for (i = 0; i < num_ctrl; i++) {
err = devm_gpio_request(&pdev->dev, ctrl[i],
"GPIO fan control");
if (err)
return err;
err = gpio_direction_output(ctrl[i],
gpio_get_value_cansleep(ctrl[i]));
for (i = 0; i < num_gpios; i++) {
/*
* The GPIO descriptors were retrieved with GPIOD_ASIS so here
* we set the GPIO into output mode, carefully preserving the
* current value by setting it to whatever it is already set
* (no surprise changes in default fan speed).
*/
err = gpiod_direction_output(gpios[i],
gpiod_get_value_cansleep(gpios[i]));
if (err)
return err;
}
fan_data->num_ctrl = num_ctrl;
fan_data->ctrl = ctrl;
fan_data->num_speed = pdata->num_speed;
fan_data->speed = pdata->speed;
fan_data->pwm_enable = true; /* Enable manual fan speed control. */
fan_data->speed_index = get_fan_speed_index(fan_data);
if (fan_data->speed_index < 0)
@ -432,67 +414,47 @@ static const struct thermal_cooling_device_ops gpio_fan_cool_ops = {
.set_cur_state = gpio_fan_set_cur_state,
};
#ifdef CONFIG_OF_GPIO
/*
* Translate OpenFirmware node properties into platform_data
*/
static int gpio_fan_get_of_pdata(struct device *dev,
struct gpio_fan_platform_data *pdata)
static int gpio_fan_get_of_data(struct gpio_fan_data *fan_data)
{
struct device_node *node;
struct gpio_fan_speed *speed;
unsigned *ctrl;
struct device *dev = fan_data->dev;
struct device_node *np = dev->of_node;
struct gpio_desc **gpios;
unsigned i;
u32 u;
struct property *prop;
const __be32 *p;
node = dev->of_node;
/* Alarm GPIO if one exists */
if (of_gpio_named_count(node, "alarm-gpios") > 0) {
struct gpio_fan_alarm *alarm;
int val;
enum of_gpio_flags flags;
alarm = devm_kzalloc(dev, sizeof(struct gpio_fan_alarm),
GFP_KERNEL);
if (!alarm)
return -ENOMEM;
val = of_get_named_gpio_flags(node, "alarm-gpios", 0, &flags);
if (val < 0)
return val;
alarm->gpio = val;
alarm->active_low = flags & OF_GPIO_ACTIVE_LOW;
pdata->alarm = alarm;
}
fan_data->alarm_gpio = devm_gpiod_get_optional(dev, "alarm", GPIOD_IN);
if (IS_ERR(fan_data->alarm_gpio))
return PTR_ERR(fan_data->alarm_gpio);
/* Fill GPIO pin array */
pdata->num_ctrl = of_gpio_count(node);
if (pdata->num_ctrl <= 0) {
if (pdata->alarm)
fan_data->num_gpios = gpiod_count(dev, NULL);
if (fan_data->num_gpios <= 0) {
if (fan_data->alarm_gpio)
return 0;
dev_err(dev, "DT properties empty / missing");
return -ENODEV;
}
ctrl = devm_kzalloc(dev, pdata->num_ctrl * sizeof(unsigned),
GFP_KERNEL);
if (!ctrl)
gpios = devm_kzalloc(dev,
fan_data->num_gpios * sizeof(struct gpio_desc *),
GFP_KERNEL);
if (!gpios)
return -ENOMEM;
for (i = 0; i < pdata->num_ctrl; i++) {
int val;
val = of_get_gpio(node, i);
if (val < 0)
return val;
ctrl[i] = val;
for (i = 0; i < fan_data->num_gpios; i++) {
gpios[i] = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS);
if (IS_ERR(gpios[i]))
return PTR_ERR(gpios[i]);
}
pdata->ctrl = ctrl;
fan_data->gpios = gpios;
/* Get number of RPM/ctrl_val pairs in speed map */
prop = of_find_property(node, "gpio-fan,speed-map", &i);
prop = of_find_property(np, "gpio-fan,speed-map", &i);
if (!prop) {
dev_err(dev, "gpio-fan,speed-map DT property missing");
return -ENODEV;
@ -502,7 +464,7 @@ static int gpio_fan_get_of_pdata(struct device *dev,
dev_err(dev, "gpio-fan,speed-map contains zero/odd number of entries");
return -ENODEV;
}
pdata->num_speed = i / 2;
fan_data->num_speed = i / 2;
/*
* Populate speed map
@ -510,12 +472,12 @@ static int gpio_fan_get_of_pdata(struct device *dev,
* this needs splitting into pairs to create gpio_fan_speed structs
*/
speed = devm_kzalloc(dev,
pdata->num_speed * sizeof(struct gpio_fan_speed),
fan_data->num_speed * sizeof(struct gpio_fan_speed),
GFP_KERNEL);
if (!speed)
return -ENOMEM;
p = NULL;
for (i = 0; i < pdata->num_speed; i++) {
for (i = 0; i < fan_data->num_speed; i++) {
p = of_prop_next_u32(prop, p, &u);
if (!p)
return -ENODEV;
@ -525,7 +487,7 @@ static int gpio_fan_get_of_pdata(struct device *dev,
return -ENODEV;
speed[i].ctrl_val = u;
}
pdata->speed = speed;
fan_data->speed = speed;
return 0;
}
@ -535,76 +497,58 @@ static const struct of_device_id of_gpio_fan_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, of_gpio_fan_match);
#endif /* CONFIG_OF_GPIO */
static int gpio_fan_probe(struct platform_device *pdev)
{
int err;
struct gpio_fan_data *fan_data;
struct gpio_fan_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
fan_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_fan_data),
fan_data = devm_kzalloc(dev, sizeof(struct gpio_fan_data),
GFP_KERNEL);
if (!fan_data)
return -ENOMEM;
#ifdef CONFIG_OF_GPIO
if (!pdata) {
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct gpio_fan_platform_data),
GFP_KERNEL);
if (!pdata)
return -ENOMEM;
fan_data->dev = dev;
err = gpio_fan_get_of_data(fan_data);
if (err)
return err;
err = gpio_fan_get_of_pdata(&pdev->dev, pdata);
if (err)
return err;
}
#else /* CONFIG_OF_GPIO */
if (!pdata)
return -EINVAL;
#endif /* CONFIG_OF_GPIO */
fan_data->pdev = pdev;
platform_set_drvdata(pdev, fan_data);
mutex_init(&fan_data->lock);
/* Configure alarm GPIO if available. */
if (pdata->alarm) {
err = fan_alarm_init(fan_data, pdata->alarm);
if (fan_data->alarm_gpio) {
err = fan_alarm_init(fan_data);
if (err)
return err;
}
/* Configure control GPIOs if available. */
if (pdata->ctrl && pdata->num_ctrl > 0) {
if (!pdata->speed || pdata->num_speed <= 1)
if (fan_data->gpios && fan_data->num_gpios > 0) {
if (!fan_data->speed || fan_data->num_speed <= 1)
return -EINVAL;
err = fan_ctrl_init(fan_data, pdata);
err = fan_ctrl_init(fan_data);
if (err)
return err;
}
/* Make this driver part of hwmon class. */
fan_data->hwmon_dev =
devm_hwmon_device_register_with_groups(&pdev->dev,
devm_hwmon_device_register_with_groups(dev,
"gpio_fan", fan_data,
gpio_fan_groups);
if (IS_ERR(fan_data->hwmon_dev))
return PTR_ERR(fan_data->hwmon_dev);
#ifdef CONFIG_OF_GPIO
/* Optional cooling device register for Device tree platforms */
fan_data->cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
fan_data->cdev = thermal_of_cooling_device_register(np,
"gpio-fan",
fan_data,
&gpio_fan_cool_ops);
#else /* CONFIG_OF_GPIO */
/* Optional cooling device register for non Device tree platforms */
fan_data->cdev = thermal_cooling_device_register("gpio-fan", fan_data,
&gpio_fan_cool_ops);
#endif /* CONFIG_OF_GPIO */
dev_info(&pdev->dev, "GPIO fan initialized\n");
dev_info(dev, "GPIO fan initialized\n");
return 0;
}
@ -616,7 +560,7 @@ static int gpio_fan_remove(struct platform_device *pdev)
if (!IS_ERR(fan_data->cdev))
thermal_cooling_device_unregister(fan_data->cdev);
if (fan_data->ctrl)
if (fan_data->gpios)
set_fan_speed(fan_data, 0);
return 0;
@ -632,7 +576,7 @@ static int gpio_fan_suspend(struct device *dev)
{
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
if (fan_data->ctrl) {
if (fan_data->gpios) {
fan_data->resume_speed = fan_data->speed_index;
set_fan_speed(fan_data, 0);
}
@ -644,7 +588,7 @@ static int gpio_fan_resume(struct device *dev)
{
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
if (fan_data->ctrl)
if (fan_data->gpios)
set_fan_speed(fan_data, fan_data->resume_speed);
return 0;
@ -663,9 +607,7 @@ static struct platform_driver gpio_fan_driver = {
.driver = {
.name = "gpio-fan",
.pm = GPIO_FAN_PM,
#ifdef CONFIG_OF_GPIO
.of_match_table = of_match_ptr(of_gpio_fan_match),
#endif
},
};

View file

@ -36,6 +36,10 @@ MODULE_PARM_DESC(force, "force loading on processors with erratum 319");
/* Provide lock for writing to NB_SMU_IND_ADDR */
static DEFINE_MUTEX(nb_smu_ind_mutex);
#ifndef PCI_DEVICE_ID_AMD_17H_DF_F3
#define PCI_DEVICE_ID_AMD_17H_DF_F3 0x1463
#endif
/* CPUID function 0x80000001, ebx */
#define CPUID_PKGTYPE_MASK 0xf0000000
#define CPUID_PKGTYPE_F 0x00000000
@ -61,31 +65,72 @@ static DEFINE_MUTEX(nb_smu_ind_mutex);
*/
#define F15H_M60H_REPORTED_TEMP_CTRL_OFFSET 0xd8200ca4
static void amd_nb_smu_index_read(struct pci_dev *pdev, unsigned int devfn,
int offset, u32 *val)
/* F17h M01h Access througn SMN */
#define F17H_M01H_REPORTED_TEMP_CTRL_OFFSET 0x00059800
struct k10temp_data {
struct pci_dev *pdev;
void (*read_tempreg)(struct pci_dev *pdev, u32 *regval);
int temp_offset;
};
struct tctl_offset {
u8 model;
char const *id;
int offset;
};
static const struct tctl_offset tctl_offset_table[] = {
{ 0x17, "AMD Ryzen 7 1600X", 20000 },
{ 0x17, "AMD Ryzen 7 1700X", 20000 },
{ 0x17, "AMD Ryzen 7 1800X", 20000 },
{ 0x17, "AMD Ryzen Threadripper 1950X", 27000 },
{ 0x17, "AMD Ryzen Threadripper 1920X", 27000 },
{ 0x17, "AMD Ryzen Threadripper 1950", 10000 },
{ 0x17, "AMD Ryzen Threadripper 1920", 10000 },
{ 0x17, "AMD Ryzen Threadripper 1910", 10000 },
};
static void read_tempreg_pci(struct pci_dev *pdev, u32 *regval)
{
pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, regval);
}
static void amd_nb_index_read(struct pci_dev *pdev, unsigned int devfn,
unsigned int base, int offset, u32 *val)
{
mutex_lock(&nb_smu_ind_mutex);
pci_bus_write_config_dword(pdev->bus, devfn,
0xb8, offset);
base, offset);
pci_bus_read_config_dword(pdev->bus, devfn,
0xbc, val);
base + 4, val);
mutex_unlock(&nb_smu_ind_mutex);
}
static void read_tempreg_nb_f15(struct pci_dev *pdev, u32 *regval)
{
amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0xb8,
F15H_M60H_REPORTED_TEMP_CTRL_OFFSET, regval);
}
static void read_tempreg_nb_f17(struct pci_dev *pdev, u32 *regval)
{
amd_nb_index_read(pdev, PCI_DEVFN(0, 0), 0x60,
F17H_M01H_REPORTED_TEMP_CTRL_OFFSET, regval);
}
static ssize_t temp1_input_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct k10temp_data *data = dev_get_drvdata(dev);
u32 regval;
struct pci_dev *pdev = dev_get_drvdata(dev);
unsigned int temp;
if (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model == 0x60) {
amd_nb_smu_index_read(pdev, PCI_DEVFN(0, 0),
F15H_M60H_REPORTED_TEMP_CTRL_OFFSET,
&regval);
} else {
pci_read_config_dword(pdev, REG_REPORTED_TEMPERATURE, &regval);
}
return sprintf(buf, "%u\n", (regval >> 21) * 125);
data->read_tempreg(data->pdev, &regval);
temp = (regval >> 21) * 125;
temp -= data->temp_offset;
return sprintf(buf, "%u\n", temp);
}
static ssize_t temp1_max_show(struct device *dev,
@ -98,11 +143,12 @@ static ssize_t show_temp_crit(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct k10temp_data *data = dev_get_drvdata(dev);
int show_hyst = attr->index;
u32 regval;
int value;
pci_read_config_dword(dev_get_drvdata(dev),
pci_read_config_dword(data->pdev,
REG_HARDWARE_THERMAL_CONTROL, &regval);
value = ((regval >> 16) & 0x7f) * 500 + 52000;
if (show_hyst)
@ -119,7 +165,8 @@ static umode_t k10temp_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct pci_dev *pdev = dev_get_drvdata(dev);
struct k10temp_data *data = dev_get_drvdata(dev);
struct pci_dev *pdev = data->pdev;
if (index >= 2) {
u32 reg_caps, reg_htc;
@ -187,7 +234,9 @@ static int k10temp_probe(struct pci_dev *pdev,
{
int unreliable = has_erratum_319(pdev);
struct device *dev = &pdev->dev;
struct k10temp_data *data;
struct device *hwmon_dev;
int i;
if (unreliable) {
if (!force) {
@ -199,7 +248,31 @@ static int k10temp_probe(struct pci_dev *pdev,
"unreliable CPU thermal sensor; check erratum 319\n");
}
hwmon_dev = devm_hwmon_device_register_with_groups(dev, "k10temp", pdev,
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->pdev = pdev;
if (boot_cpu_data.x86 == 0x15 && (boot_cpu_data.x86_model == 0x60 ||
boot_cpu_data.x86_model == 0x70))
data->read_tempreg = read_tempreg_nb_f15;
else if (boot_cpu_data.x86 == 0x17)
data->read_tempreg = read_tempreg_nb_f17;
else
data->read_tempreg = read_tempreg_pci;
for (i = 0; i < ARRAY_SIZE(tctl_offset_table); i++) {
const struct tctl_offset *entry = &tctl_offset_table[i];
if (boot_cpu_data.x86 == entry->model &&
strstr(boot_cpu_data.x86_model_id, entry->id)) {
data->temp_offset = entry->offset;
break;
}
}
hwmon_dev = devm_hwmon_device_register_with_groups(dev, "k10temp", data,
k10temp_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
@ -214,6 +287,7 @@ static const struct pci_device_id k10temp_id_table[] = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_17H_DF_F3) },
{}
};
MODULE_DEVICE_TABLE(pci, k10temp_id_table);

View file

@ -303,10 +303,20 @@ static const struct i2c_device_id max1619_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max1619_id);
#ifdef CONFIG_OF
static const struct of_device_id max1619_of_match[] = {
{ .compatible = "maxim,max1619", },
{},
};
MODULE_DEVICE_TABLE(of, max1619_of_match);
#endif
static struct i2c_driver max1619_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "max1619",
.of_match_table = of_match_ptr(max1619_of_match),
},
.probe = max1619_probe,
.id_table = max1619_id,

593
drivers/hwmon/max6621.c Normal file
View file

@ -0,0 +1,593 @@
/*
* Hardware monitoring driver for Maxim MAX6621
*
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
*
* 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.
*/
#include <linux/bitops.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#define MAX6621_DRV_NAME "max6621"
#define MAX6621_TEMP_INPUT_REG_NUM 9
#define MAX6621_TEMP_INPUT_MIN -127000
#define MAX6621_TEMP_INPUT_MAX 128000
#define MAX6621_TEMP_ALERT_CHAN_SHIFT 1
#define MAX6621_TEMP_S0D0_REG 0x00
#define MAX6621_TEMP_S0D1_REG 0x01
#define MAX6621_TEMP_S1D0_REG 0x02
#define MAX6621_TEMP_S1D1_REG 0x03
#define MAX6621_TEMP_S2D0_REG 0x04
#define MAX6621_TEMP_S2D1_REG 0x05
#define MAX6621_TEMP_S3D0_REG 0x06
#define MAX6621_TEMP_S3D1_REG 0x07
#define MAX6621_TEMP_MAX_REG 0x08
#define MAX6621_TEMP_MAX_ADDR_REG 0x0a
#define MAX6621_TEMP_ALERT_CAUSE_REG 0x0b
#define MAX6621_CONFIG0_REG 0x0c
#define MAX6621_CONFIG1_REG 0x0d
#define MAX6621_CONFIG2_REG 0x0e
#define MAX6621_CONFIG3_REG 0x0f
#define MAX6621_TEMP_S0_ALERT_REG 0x10
#define MAX6621_TEMP_S1_ALERT_REG 0x11
#define MAX6621_TEMP_S2_ALERT_REG 0x12
#define MAX6621_TEMP_S3_ALERT_REG 0x13
#define MAX6621_CLEAR_ALERT_REG 0x15
#define MAX6621_REG_MAX (MAX6621_CLEAR_ALERT_REG + 1)
#define MAX6621_REG_TEMP_SHIFT 0x06
#define MAX6621_ENABLE_TEMP_ALERTS_BIT 4
#define MAX6621_ENABLE_I2C_CRC_BIT 5
#define MAX6621_ENABLE_ALTERNATE_DATA 6
#define MAX6621_ENABLE_LOCKUP_TO 7
#define MAX6621_ENABLE_S0D0_BIT 8
#define MAX6621_ENABLE_S3D1_BIT 15
#define MAX6621_ENABLE_TEMP_ALL GENMASK(MAX6621_ENABLE_S3D1_BIT, \
MAX6621_ENABLE_S0D0_BIT)
#define MAX6621_POLL_DELAY_MASK 0x5
#define MAX6621_CONFIG0_INIT (MAX6621_ENABLE_TEMP_ALL | \
BIT(MAX6621_ENABLE_LOCKUP_TO) | \
BIT(MAX6621_ENABLE_I2C_CRC_BIT) | \
MAX6621_POLL_DELAY_MASK)
#define MAX6621_PECI_BIT_TIME 0x2
#define MAX6621_PECI_RETRY_NUM 0x3
#define MAX6621_CONFIG1_INIT ((MAX6621_PECI_BIT_TIME << 8) | \
MAX6621_PECI_RETRY_NUM)
/* Error codes */
#define MAX6621_TRAN_FAILED 0x8100 /*
* PECI transaction failed for more
* than the configured number of
* consecutive retries.
*/
#define MAX6621_POOL_DIS 0x8101 /*
* Polling disabled for requested
* socket/domain.
*/
#define MAX6621_POOL_UNCOMPLETE 0x8102 /*
* First poll not yet completed for
* requested socket/domain (on
* startup).
*/
#define MAX6621_SD_DIS 0x8103 /*
* Read maximum temperature requested,
* but no sockets/domains enabled or
* all enabled sockets/domains have
* errors; or read maximum temperature
* address requested, but read maximum
* temperature was not called.
*/
#define MAX6621_ALERT_DIS 0x8104 /*
* Get alert socket/domain requested,
* but no alert active.
*/
#define MAX6621_PECI_ERR_MIN 0x8000 /* Intel spec PECI error min value. */
#define MAX6621_PECI_ERR_MAX 0x80ff /* Intel spec PECI error max value. */
static const u32 max6621_temp_regs[] = {
MAX6621_TEMP_MAX_REG, MAX6621_TEMP_S0D0_REG, MAX6621_TEMP_S1D0_REG,
MAX6621_TEMP_S2D0_REG, MAX6621_TEMP_S3D0_REG, MAX6621_TEMP_S0D1_REG,
MAX6621_TEMP_S1D1_REG, MAX6621_TEMP_S2D1_REG, MAX6621_TEMP_S3D1_REG,
};
static const char *const max6621_temp_labels[] = {
"maximum",
"socket0_0",
"socket1_0",
"socket2_0",
"socket3_0",
"socket0_1",
"socket1_1",
"socket2_1",
"socket3_1",
};
static const int max6621_temp_alert_chan2reg[] = {
MAX6621_TEMP_S0_ALERT_REG,
MAX6621_TEMP_S1_ALERT_REG,
MAX6621_TEMP_S2_ALERT_REG,
MAX6621_TEMP_S3_ALERT_REG,
};
/**
* struct max6621_data - private data:
*
* @client: I2C client;
* @regmap: register map handle;
* @input_chan2reg: mapping from channel to register;
*/
struct max6621_data {
struct i2c_client *client;
struct regmap *regmap;
int input_chan2reg[MAX6621_TEMP_INPUT_REG_NUM + 1];
};
static long max6621_temp_mc2reg(long val)
{
return (val / 1000L) << MAX6621_REG_TEMP_SHIFT;
}
static umode_t
max6621_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,
int channel)
{
/* Skip channels which are not physically conncted. */
if (((struct max6621_data *)data)->input_chan2reg[channel] < 0)
return 0;
switch (type) {
case hwmon_temp:
switch (attr) {
case hwmon_temp_input:
case hwmon_temp_label:
case hwmon_temp_crit_alarm:
return 0444;
case hwmon_temp_offset:
case hwmon_temp_crit:
return 0644;
default:
break;
}
default:
break;
}
return 0;
}
static int max6621_verify_reg_data(struct device *dev, int regval)
{
if (regval >= MAX6621_PECI_ERR_MIN &&
regval <= MAX6621_PECI_ERR_MAX) {
dev_dbg(dev, "PECI error code - err 0x%04x.\n",
regval);
return -EIO;
}
switch (regval) {
case MAX6621_TRAN_FAILED:
dev_dbg(dev, "PECI transaction failed - err 0x%04x.\n",
regval);
return -EIO;
case MAX6621_POOL_DIS:
dev_dbg(dev, "Polling disabled - err 0x%04x.\n", regval);
return -EOPNOTSUPP;
case MAX6621_POOL_UNCOMPLETE:
dev_dbg(dev, "First poll not completed on startup - err 0x%04x.\n",
regval);
return -EIO;
case MAX6621_SD_DIS:
dev_dbg(dev, "Resource is disabled - err 0x%04x.\n", regval);
return -EOPNOTSUPP;
case MAX6621_ALERT_DIS:
dev_dbg(dev, "No alert active - err 0x%04x.\n", regval);
return -EOPNOTSUPP;
default:
return 0;
}
}
static int
max6621_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
struct max6621_data *data = dev_get_drvdata(dev);
u32 regval;
int reg;
s8 temp;
int ret;
switch (type) {
case hwmon_temp:
switch (attr) {
case hwmon_temp_input:
reg = data->input_chan2reg[channel];
ret = regmap_read(data->regmap, reg, &regval);
if (ret)
return ret;
ret = max6621_verify_reg_data(dev, regval);
if (ret)
return ret;
/*
* Bit MAX6621_REG_TEMP_SHIFT represents 1 degree step.
* The temperature is given in two's complement and 8
* bits is used for the register conversion.
*/
temp = (regval >> MAX6621_REG_TEMP_SHIFT);
*val = temp * 1000L;
break;
case hwmon_temp_offset:
ret = regmap_read(data->regmap, MAX6621_CONFIG2_REG,
&regval);
if (ret)
return ret;
ret = max6621_verify_reg_data(dev, regval);
if (ret)
return ret;
*val = (regval >> MAX6621_REG_TEMP_SHIFT) *
1000L;
break;
case hwmon_temp_crit:
channel -= MAX6621_TEMP_ALERT_CHAN_SHIFT;
reg = max6621_temp_alert_chan2reg[channel];
ret = regmap_read(data->regmap, reg, &regval);
if (ret)
return ret;
ret = max6621_verify_reg_data(dev, regval);
if (ret)
return ret;
*val = regval * 1000L;
break;
case hwmon_temp_crit_alarm:
/*
* Set val to zero to recover the case, when reading
* MAX6621_TEMP_ALERT_CAUSE_REG results in for example
* MAX6621_ALERT_DIS. Reading will return with error,
* but in such case alarm should be returned as 0.
*/
*val = 0;
ret = regmap_read(data->regmap,
MAX6621_TEMP_ALERT_CAUSE_REG,
&regval);
if (ret)
return ret;
ret = max6621_verify_reg_data(dev, regval);
if (ret) {
/* Do not report error if alert is disabled. */
if (regval == MAX6621_ALERT_DIS)
return 0;
else
return ret;
}
/*
* Clear the alert automatically, using send-byte
* smbus protocol for clearing alert.
*/
if (regval) {
ret = i2c_smbus_write_byte(data->client,
MAX6621_CLEAR_ALERT_REG);
if (ret)
return ret;
}
*val = !!regval;
break;
default:
return -EOPNOTSUPP;
}
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int
max6621_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long val)
{
struct max6621_data *data = dev_get_drvdata(dev);
u32 reg;
switch (type) {
case hwmon_temp:
switch (attr) {
case hwmon_temp_offset:
/* Clamp to allowed range to prevent overflow. */
val = clamp_val(val, MAX6621_TEMP_INPUT_MIN,
MAX6621_TEMP_INPUT_MAX);
val = max6621_temp_mc2reg(val);
return regmap_write(data->regmap,
MAX6621_CONFIG2_REG, val);
case hwmon_temp_crit:
channel -= MAX6621_TEMP_ALERT_CHAN_SHIFT;
reg = max6621_temp_alert_chan2reg[channel];
/* Clamp to allowed range to prevent overflow. */
val = clamp_val(val, MAX6621_TEMP_INPUT_MIN,
MAX6621_TEMP_INPUT_MAX);
val = val / 1000L;
return regmap_write(data->regmap, reg, val);
default:
return -EOPNOTSUPP;
}
break;
default:
return -EOPNOTSUPP;
}
return -EOPNOTSUPP;
}
static int
max6621_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, const char **str)
{
switch (type) {
case hwmon_temp:
switch (attr) {
case hwmon_temp_label:
*str = max6621_temp_labels[channel];
return 0;
default:
return -EOPNOTSUPP;
}
break;
default:
return -EOPNOTSUPP;
}
return -EOPNOTSUPP;
}
static bool max6621_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX6621_CONFIG0_REG:
case MAX6621_CONFIG1_REG:
case MAX6621_CONFIG2_REG:
case MAX6621_CONFIG3_REG:
case MAX6621_TEMP_S0_ALERT_REG:
case MAX6621_TEMP_S1_ALERT_REG:
case MAX6621_TEMP_S2_ALERT_REG:
case MAX6621_TEMP_S3_ALERT_REG:
case MAX6621_TEMP_ALERT_CAUSE_REG:
return true;
}
return false;
}
static bool max6621_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX6621_TEMP_S0D0_REG:
case MAX6621_TEMP_S0D1_REG:
case MAX6621_TEMP_S1D0_REG:
case MAX6621_TEMP_S1D1_REG:
case MAX6621_TEMP_S2D0_REG:
case MAX6621_TEMP_S2D1_REG:
case MAX6621_TEMP_S3D0_REG:
case MAX6621_TEMP_S3D1_REG:
case MAX6621_TEMP_MAX_REG:
case MAX6621_TEMP_MAX_ADDR_REG:
case MAX6621_CONFIG0_REG:
case MAX6621_CONFIG1_REG:
case MAX6621_CONFIG2_REG:
case MAX6621_CONFIG3_REG:
case MAX6621_TEMP_S0_ALERT_REG:
case MAX6621_TEMP_S1_ALERT_REG:
case MAX6621_TEMP_S2_ALERT_REG:
case MAX6621_TEMP_S3_ALERT_REG:
return true;
}
return false;
}
static bool max6621_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MAX6621_TEMP_S0D0_REG:
case MAX6621_TEMP_S0D1_REG:
case MAX6621_TEMP_S1D0_REG:
case MAX6621_TEMP_S1D1_REG:
case MAX6621_TEMP_S2D0_REG:
case MAX6621_TEMP_S2D1_REG:
case MAX6621_TEMP_S3D0_REG:
case MAX6621_TEMP_S3D1_REG:
case MAX6621_TEMP_MAX_REG:
case MAX6621_TEMP_S0_ALERT_REG:
case MAX6621_TEMP_S1_ALERT_REG:
case MAX6621_TEMP_S2_ALERT_REG:
case MAX6621_TEMP_S3_ALERT_REG:
case MAX6621_TEMP_ALERT_CAUSE_REG:
return true;
}
return false;
}
static const struct reg_default max6621_regmap_default[] = {
{ MAX6621_CONFIG0_REG, MAX6621_CONFIG0_INIT },
{ MAX6621_CONFIG1_REG, MAX6621_CONFIG1_INIT },
};
static const struct regmap_config max6621_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
.max_register = MAX6621_REG_MAX,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
.cache_type = REGCACHE_FLAT,
.writeable_reg = max6621_writeable_reg,
.readable_reg = max6621_readable_reg,
.volatile_reg = max6621_volatile_reg,
.reg_defaults = max6621_regmap_default,
.num_reg_defaults = ARRAY_SIZE(max6621_regmap_default),
};
static u32 max6621_chip_config[] = {
HWMON_C_REGISTER_TZ,
0
};
static const struct hwmon_channel_info max6621_chip = {
.type = hwmon_chip,
.config = max6621_chip_config,
};
static const u32 max6621_temp_config[] = {
HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_OFFSET,
HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL,
0
};
static const struct hwmon_channel_info max6621_temp = {
.type = hwmon_temp,
.config = max6621_temp_config,
};
static const struct hwmon_channel_info *max6621_info[] = {
&max6621_chip,
&max6621_temp,
NULL
};
static const struct hwmon_ops max6621_hwmon_ops = {
.read = max6621_read,
.write = max6621_write,
.read_string = max6621_read_string,
.is_visible = max6621_is_visible,
};
static const struct hwmon_chip_info max6621_chip_info = {
.ops = &max6621_hwmon_ops,
.info = max6621_info,
};
static int max6621_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct max6621_data *data;
struct device *hwmon_dev;
int i;
int ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->regmap = devm_regmap_init_i2c(client, &max6621_regmap_config);
if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap);
i2c_set_clientdata(client, data);
data->client = client;
/* Set CONFIG0 register masking temperature alerts and PEC. */
ret = regmap_write(data->regmap, MAX6621_CONFIG0_REG,
MAX6621_CONFIG0_INIT);
if (ret)
return ret;
/* Set CONFIG1 register for PEC access retry number. */
ret = regmap_write(data->regmap, MAX6621_CONFIG1_REG,
MAX6621_CONFIG1_INIT);
if (ret)
return ret;
/* Sync registers with hardware. */
regcache_mark_dirty(data->regmap);
ret = regcache_sync(data->regmap);
if (ret)
return ret;
/* Verify which temperature input registers are enabled. */
for (i = 0; i < MAX6621_TEMP_INPUT_REG_NUM; i++) {
ret = i2c_smbus_read_word_data(client, max6621_temp_regs[i]);
if (ret < 0)
return ret;
ret = max6621_verify_reg_data(dev, ret);
if (ret) {
data->input_chan2reg[i] = -1;
continue;
}
data->input_chan2reg[i] = max6621_temp_regs[i];
}
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
data,
&max6621_chip_info,
NULL);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct i2c_device_id max6621_id[] = {
{ MAX6621_DRV_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max6621_id);
static const struct of_device_id max6621_of_match[] = {
{ .compatible = "maxim,max6621" },
{ }
};
MODULE_DEVICE_TABLE(of, max6621_of_match);
static struct i2c_driver max6621_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = MAX6621_DRV_NAME,
.of_match_table = of_match_ptr(max6621_of_match),
},
.probe = max6621_probe,
.id_table = max6621_id,
};
module_i2c_driver(max6621_driver);
MODULE_AUTHOR("Vadim Pasternak <[email protected]>");
MODULE_DESCRIPTION("Driver for Maxim MAX6621");
MODULE_LICENSE("GPL");

View file

@ -114,6 +114,16 @@ config SENSORS_MAX20751
This driver can also be built as a module. If so, the module will
be called max20751.
config SENSORS_MAX31785
tristate "Maxim MAX31785 and compatibles"
default n
help
If you say yes here you get hardware monitoring support for Maxim
MAX31785.
This driver can also be built as a module. If so, the module will
be called max31785.
config SENSORS_MAX34440
tristate "Maxim MAX34440 and compatibles"
default n

View file

@ -13,6 +13,7 @@ obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o
obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
obj-$(CONFIG_SENSORS_MAX20751) += max20751.o
obj-$(CONFIG_SENSORS_MAX31785) += max31785.o
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o

View file

@ -0,0 +1,116 @@
/*
* Copyright (C) 2017 IBM Corp.
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include "pmbus.h"
enum max31785_regs {
MFR_REVISION = 0x9b,
};
#define MAX31785_NR_PAGES 23
#define MAX31785_FAN_FUNCS \
(PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12)
#define MAX31785_TEMP_FUNCS \
(PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP)
#define MAX31785_VOUT_FUNCS \
(PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT)
static const struct pmbus_driver_info max31785_info = {
.pages = MAX31785_NR_PAGES,
/* RPM */
.format[PSC_FAN] = direct,
.m[PSC_FAN] = 1,
.b[PSC_FAN] = 0,
.R[PSC_FAN] = 0,
.func[0] = MAX31785_FAN_FUNCS,
.func[1] = MAX31785_FAN_FUNCS,
.func[2] = MAX31785_FAN_FUNCS,
.func[3] = MAX31785_FAN_FUNCS,
.func[4] = MAX31785_FAN_FUNCS,
.func[5] = MAX31785_FAN_FUNCS,
.format[PSC_TEMPERATURE] = direct,
.m[PSC_TEMPERATURE] = 1,
.b[PSC_TEMPERATURE] = 0,
.R[PSC_TEMPERATURE] = 2,
.func[6] = MAX31785_TEMP_FUNCS,
.func[7] = MAX31785_TEMP_FUNCS,
.func[8] = MAX31785_TEMP_FUNCS,
.func[9] = MAX31785_TEMP_FUNCS,
.func[10] = MAX31785_TEMP_FUNCS,
.func[11] = MAX31785_TEMP_FUNCS,
.func[12] = MAX31785_TEMP_FUNCS,
.func[13] = MAX31785_TEMP_FUNCS,
.func[14] = MAX31785_TEMP_FUNCS,
.func[15] = MAX31785_TEMP_FUNCS,
.func[16] = MAX31785_TEMP_FUNCS,
.format[PSC_VOLTAGE_OUT] = direct,
.m[PSC_VOLTAGE_OUT] = 1,
.b[PSC_VOLTAGE_OUT] = 0,
.R[PSC_VOLTAGE_OUT] = 0,
.func[17] = MAX31785_VOUT_FUNCS,
.func[18] = MAX31785_VOUT_FUNCS,
.func[19] = MAX31785_VOUT_FUNCS,
.func[20] = MAX31785_VOUT_FUNCS,
.func[21] = MAX31785_VOUT_FUNCS,
.func[22] = MAX31785_VOUT_FUNCS,
};
static int max31785_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct pmbus_driver_info *info;
s64 ret;
info = devm_kzalloc(dev, sizeof(struct pmbus_driver_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
*info = max31785_info;
ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255);
if (ret < 0)
return ret;
return pmbus_do_probe(client, id, info);
}
static const struct i2c_device_id max31785_id[] = {
{ "max31785", 0 },
{ "max31785a", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, max31785_id);
static struct i2c_driver max31785_driver = {
.driver = {
.name = "max31785",
},
.probe = max31785_probe,
.remove = pmbus_do_remove,
.id_table = max31785_id,
};
module_i2c_driver(max31785_driver);
MODULE_AUTHOR("Andrew Jeffery <[email protected]>");
MODULE_DESCRIPTION("PMBus driver for the Maxim MAX31785");
MODULE_LICENSE("GPL");

View file

@ -404,9 +404,9 @@ extern const struct regulator_ops pmbus_regulator_ops;
/* Function declarations */
void pmbus_clear_cache(struct i2c_client *client);
int pmbus_set_page(struct i2c_client *client, u8 page);
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_set_page(struct i2c_client *client, int page);
int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg);
int pmbus_write_word_data(struct i2c_client *client, int 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,

View file

@ -136,13 +136,13 @@ void pmbus_clear_cache(struct i2c_client *client)
}
EXPORT_SYMBOL_GPL(pmbus_clear_cache);
int pmbus_set_page(struct i2c_client *client, u8 page)
int pmbus_set_page(struct i2c_client *client, int page)
{
struct pmbus_data *data = i2c_get_clientdata(client);
int rv = 0;
int newpage;
if (page != data->currpage) {
if (page >= 0 && page != data->currpage) {
rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
if (newpage != page)
@ -158,11 +158,9 @@ int pmbus_write_byte(struct i2c_client *client, int page, u8 value)
{
int rv;
if (page >= 0) {
rv = pmbus_set_page(client, page);
if (rv < 0)
return rv;
}
rv = pmbus_set_page(client, page);
if (rv < 0)
return rv;
return i2c_smbus_write_byte(client, value);
}
@ -186,7 +184,8 @@ static int _pmbus_write_byte(struct i2c_client *client, int page, u8 value)
return pmbus_write_byte(client, page, value);
}
int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word)
int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg,
u16 word)
{
int rv;
@ -219,7 +218,7 @@ static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg,
return pmbus_write_word_data(client, page, reg, word);
}
int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg)
int pmbus_read_word_data(struct i2c_client *client, int page, u8 reg)
{
int rv;
@ -255,11 +254,9 @@ int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
{
int rv;
if (page >= 0) {
rv = pmbus_set_page(client, page);
if (rv < 0)
return rv;
}
rv = pmbus_set_page(client, page);
if (rv < 0)
return rv;
return i2c_smbus_read_byte_data(client, reg);
}

View file

@ -18,13 +18,11 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/mutex.h>
#include <linux/platform_data/sht15.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/delay.h>
@ -34,7 +32,8 @@
#include <linux/slab.h>
#include <linux/atomic.h>
#include <linux/bitrev.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
/* Commands */
#define SHT15_MEASURE_TEMP 0x03
@ -122,7 +121,8 @@ static const u8 sht15_crc8_table[] = {
/**
* struct sht15_data - device instance specific data
* @pdata: platform data (gpio's etc).
* @sck: clock GPIO line
* @data: data GPIO line
* @read_work: bh of interrupt handler.
* @wait_queue: wait queue for getting values from device.
* @val_temp: last temperature value read from device.
@ -150,7 +150,8 @@ static const u8 sht15_crc8_table[] = {
* @interrupt_handled: flag used to indicate a handler has been scheduled.
*/
struct sht15_data {
struct sht15_platform_data *pdata;
struct gpio_desc *sck;
struct gpio_desc *data;
struct work_struct read_work;
wait_queue_head_t wait_queue;
uint16_t val_temp;
@ -205,16 +206,16 @@ static int sht15_connection_reset(struct sht15_data *data)
{
int i, err;
err = gpio_direction_output(data->pdata->gpio_data, 1);
err = gpiod_direction_output(data->data, 1);
if (err)
return err;
ndelay(SHT15_TSCKL);
gpio_set_value(data->pdata->gpio_sck, 0);
gpiod_set_value(data->sck, 0);
ndelay(SHT15_TSCKL);
for (i = 0; i < 9; ++i) {
gpio_set_value(data->pdata->gpio_sck, 1);
gpiod_set_value(data->sck, 1);
ndelay(SHT15_TSCKH);
gpio_set_value(data->pdata->gpio_sck, 0);
gpiod_set_value(data->sck, 0);
ndelay(SHT15_TSCKL);
}
return 0;
@ -227,11 +228,11 @@ static int sht15_connection_reset(struct sht15_data *data)
*/
static inline void sht15_send_bit(struct sht15_data *data, int val)
{
gpio_set_value(data->pdata->gpio_data, val);
gpiod_set_value(data->data, val);
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 1);
gpiod_set_value(data->sck, 1);
ndelay(SHT15_TSCKH);
gpio_set_value(data->pdata->gpio_sck, 0);
gpiod_set_value(data->sck, 0);
ndelay(SHT15_TSCKL); /* clock low time */
}
@ -248,23 +249,23 @@ static int sht15_transmission_start(struct sht15_data *data)
int err;
/* ensure data is high and output */
err = gpio_direction_output(data->pdata->gpio_data, 1);
err = gpiod_direction_output(data->data, 1);
if (err)
return err;
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 0);
gpiod_set_value(data->sck, 0);
ndelay(SHT15_TSCKL);
gpio_set_value(data->pdata->gpio_sck, 1);
gpiod_set_value(data->sck, 1);
ndelay(SHT15_TSCKH);
gpio_set_value(data->pdata->gpio_data, 0);
gpiod_set_value(data->data, 0);
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 0);
gpiod_set_value(data->sck, 0);
ndelay(SHT15_TSCKL);
gpio_set_value(data->pdata->gpio_sck, 1);
gpiod_set_value(data->sck, 1);
ndelay(SHT15_TSCKH);
gpio_set_value(data->pdata->gpio_data, 1);
gpiod_set_value(data->data, 1);
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 0);
gpiod_set_value(data->sck, 0);
ndelay(SHT15_TSCKL);
return 0;
}
@ -292,20 +293,20 @@ static int sht15_wait_for_response(struct sht15_data *data)
{
int err;
err = gpio_direction_input(data->pdata->gpio_data);
err = gpiod_direction_input(data->data);
if (err)
return err;
gpio_set_value(data->pdata->gpio_sck, 1);
gpiod_set_value(data->sck, 1);
ndelay(SHT15_TSCKH);
if (gpio_get_value(data->pdata->gpio_data)) {
gpio_set_value(data->pdata->gpio_sck, 0);
if (gpiod_get_value(data->data)) {
gpiod_set_value(data->sck, 0);
dev_err(data->dev, "Command not acknowledged\n");
err = sht15_connection_reset(data);
if (err)
return err;
return -EIO;
}
gpio_set_value(data->pdata->gpio_sck, 0);
gpiod_set_value(data->sck, 0);
ndelay(SHT15_TSCKL);
return 0;
}
@ -360,17 +361,17 @@ static int sht15_ack(struct sht15_data *data)
{
int err;
err = gpio_direction_output(data->pdata->gpio_data, 0);
err = gpiod_direction_output(data->data, 0);
if (err)
return err;
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 1);
gpiod_set_value(data->sck, 1);
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 0);
gpiod_set_value(data->sck, 0);
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_data, 1);
gpiod_set_value(data->data, 1);
return gpio_direction_input(data->pdata->gpio_data);
return gpiod_direction_input(data->data);
}
/**
@ -383,13 +384,13 @@ static int sht15_end_transmission(struct sht15_data *data)
{
int err;
err = gpio_direction_output(data->pdata->gpio_data, 1);
err = gpiod_direction_output(data->data, 1);
if (err)
return err;
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 1);
gpiod_set_value(data->sck, 1);
ndelay(SHT15_TSCKH);
gpio_set_value(data->pdata->gpio_sck, 0);
gpiod_set_value(data->sck, 0);
ndelay(SHT15_TSCKL);
return 0;
}
@ -405,10 +406,10 @@ static u8 sht15_read_byte(struct sht15_data *data)
for (i = 0; i < 8; ++i) {
byte <<= 1;
gpio_set_value(data->pdata->gpio_sck, 1);
gpiod_set_value(data->sck, 1);
ndelay(SHT15_TSCKH);
byte |= !!gpio_get_value(data->pdata->gpio_data);
gpio_set_value(data->pdata->gpio_sck, 0);
byte |= !!gpiod_get_value(data->data);
gpiod_set_value(data->sck, 0);
ndelay(SHT15_TSCKL);
}
return byte;
@ -428,7 +429,7 @@ static int sht15_send_status(struct sht15_data *data, u8 status)
err = sht15_send_cmd(data, SHT15_WRITE_STATUS);
if (err)
return err;
err = gpio_direction_output(data->pdata->gpio_data, 1);
err = gpiod_direction_output(data->data, 1);
if (err)
return err;
ndelay(SHT15_TSU);
@ -528,14 +529,14 @@ static int sht15_measurement(struct sht15_data *data,
if (ret)
return ret;
ret = gpio_direction_input(data->pdata->gpio_data);
ret = gpiod_direction_input(data->data);
if (ret)
return ret;
atomic_set(&data->interrupt_handled, 0);
enable_irq(gpio_to_irq(data->pdata->gpio_data));
if (gpio_get_value(data->pdata->gpio_data) == 0) {
disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
enable_irq(gpiod_to_irq(data->data));
if (gpiod_get_value(data->data) == 0) {
disable_irq_nosync(gpiod_to_irq(data->data));
/* Only relevant if the interrupt hasn't occurred. */
if (!atomic_read(&data->interrupt_handled))
schedule_work(&data->read_work);
@ -547,7 +548,7 @@ static int sht15_measurement(struct sht15_data *data,
data->state = SHT15_READING_NOTHING;
return -EIO;
} else if (ret == 0) { /* timeout occurred */
disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
disable_irq_nosync(gpiod_to_irq(data->data));
ret = sht15_connection_reset(data);
if (ret)
return ret;
@ -826,15 +827,15 @@ static void sht15_bh_read_data(struct work_struct *work_s)
read_work);
/* Firstly, verify the line is low */
if (gpio_get_value(data->pdata->gpio_data)) {
if (gpiod_get_value(data->data)) {
/*
* If not, then start the interrupt again - care here as could
* have gone low in meantime so verify it hasn't!
*/
atomic_set(&data->interrupt_handled, 0);
enable_irq(gpio_to_irq(data->pdata->gpio_data));
enable_irq(gpiod_to_irq(data->data));
/* If still not occurred or another handler was scheduled */
if (gpio_get_value(data->pdata->gpio_data)
if (gpiod_get_value(data->data)
|| atomic_read(&data->interrupt_handled))
return;
}
@ -918,53 +919,12 @@ static const struct of_device_id sht15_dt_match[] = {
{ },
};
MODULE_DEVICE_TABLE(of, sht15_dt_match);
/*
* This function returns NULL if pdev isn't a device instatiated by dt,
* a pointer to pdata if it could successfully get all information
* from dt or a negative ERR_PTR() on error.
*/
static struct sht15_platform_data *sht15_probe_dt(struct device *dev)
{
struct device_node *np = dev->of_node;
struct sht15_platform_data *pdata;
/* no device tree device */
if (!np)
return NULL;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
pdata->gpio_data = of_get_named_gpio(np, "data-gpios", 0);
if (pdata->gpio_data < 0) {
if (pdata->gpio_data != -EPROBE_DEFER)
dev_err(dev, "data-gpios not found\n");
return ERR_PTR(pdata->gpio_data);
}
pdata->gpio_sck = of_get_named_gpio(np, "clk-gpios", 0);
if (pdata->gpio_sck < 0) {
if (pdata->gpio_sck != -EPROBE_DEFER)
dev_err(dev, "clk-gpios not found\n");
return ERR_PTR(pdata->gpio_sck);
}
return pdata;
}
#else
static inline struct sht15_platform_data *sht15_probe_dt(struct device *dev)
{
return NULL;
}
#endif
static int sht15_probe(struct platform_device *pdev)
{
int ret;
struct sht15_data *data;
u8 status = 0;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
@ -977,25 +937,6 @@ static int sht15_probe(struct platform_device *pdev)
data->dev = &pdev->dev;
init_waitqueue_head(&data->wait_queue);
data->pdata = sht15_probe_dt(&pdev->dev);
if (IS_ERR(data->pdata))
return PTR_ERR(data->pdata);
if (data->pdata == NULL) {
data->pdata = dev_get_platdata(&pdev->dev);
if (data->pdata == NULL) {
dev_err(&pdev->dev, "no platform data supplied\n");
return -EINVAL;
}
}
data->supply_uv = data->pdata->supply_mv * 1000;
if (data->pdata->checksum)
data->checksumming = true;
if (data->pdata->no_otp_reload)
status |= SHT15_STATUS_NO_OTP_RELOAD;
if (data->pdata->low_resolution)
status |= SHT15_STATUS_LOW_RESOLUTION;
/*
* If a regulator is available,
* query what the supply voltage actually is!
@ -1030,21 +971,20 @@ static int sht15_probe(struct platform_device *pdev)
}
/* Try requesting the GPIOs */
ret = devm_gpio_request_one(&pdev->dev, data->pdata->gpio_sck,
GPIOF_OUT_INIT_LOW, "SHT15 sck");
if (ret) {
data->sck = devm_gpiod_get(&pdev->dev, "clk", GPIOD_OUT_LOW);
if (IS_ERR(data->sck)) {
ret = PTR_ERR(data->sck);
dev_err(&pdev->dev, "clock line GPIO request failed\n");
goto err_release_reg;
}
ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
"SHT15 data");
if (ret) {
data->data = devm_gpiod_get(&pdev->dev, "data", GPIOD_IN);
if (IS_ERR(data->data)) {
ret = PTR_ERR(data->data);
dev_err(&pdev->dev, "data line GPIO request failed\n");
goto err_release_reg;
}
ret = devm_request_irq(&pdev->dev, gpio_to_irq(data->pdata->gpio_data),
ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->data),
sht15_interrupt_fired,
IRQF_TRIGGER_FALLING,
"sht15 data",
@ -1053,7 +993,7 @@ static int sht15_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to get irq for data line\n");
goto err_release_reg;
}
disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
disable_irq_nosync(gpiod_to_irq(data->data));
ret = sht15_connection_reset(data);
if (ret)
goto err_release_reg;
@ -1061,13 +1001,6 @@ static int sht15_probe(struct platform_device *pdev)
if (ret)
goto err_release_reg;
/* write status with platform data options */
if (status) {
ret = sht15_send_status(data, status);
if (ret)
goto err_release_reg;
}
ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
if (ret) {
dev_err(&pdev->dev, "sysfs create failed\n");

View file

@ -396,7 +396,7 @@ static ssize_t show_max_alarm(struct device *dev, struct device_attribute *attr,
if (ret < 0)
return ret;
return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->max_alert);
return snprintf(buf, PAGE_SIZE, "%d\n", priv->max_alert);
}
static ssize_t show_min_alarm(struct device *dev, struct device_attribute *attr,
@ -413,7 +413,7 @@ static ssize_t show_min_alarm(struct device *dev, struct device_attribute *attr,
if (ret < 0)
return ret;
return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->min_alert);
return snprintf(buf, PAGE_SIZE, "%d\n", priv->min_alert);
}
static ssize_t show_input(struct device *dev, struct device_attribute *attr,
@ -428,7 +428,7 @@ static ssize_t show_input(struct device *dev, struct device_attribute *attr,
if (ret < 0)
return ret;
return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->temp);
return snprintf(buf, PAGE_SIZE, "%d\n", priv->temp);
}
static ssize_t show_therm(struct device *dev, struct device_attribute *attr,
@ -436,7 +436,7 @@ static ssize_t show_therm(struct device *dev, struct device_attribute *attr,
{
struct stts751_priv *priv = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->therm);
return snprintf(buf, PAGE_SIZE, "%d\n", priv->therm);
}
static ssize_t set_therm(struct device *dev, struct device_attribute *attr,
@ -478,7 +478,7 @@ static ssize_t show_hyst(struct device *dev, struct device_attribute *attr,
{
struct stts751_priv *priv = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->hyst);
return snprintf(buf, PAGE_SIZE, "%d\n", priv->hyst);
}
static ssize_t set_hyst(struct device *dev, struct device_attribute *attr,
@ -518,7 +518,7 @@ static ssize_t show_therm_trip(struct device *dev,
if (ret < 0)
return ret;
return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->therm_trip);
return snprintf(buf, PAGE_SIZE, "%d\n", priv->therm_trip);
}
static ssize_t show_max(struct device *dev, struct device_attribute *attr,
@ -526,7 +526,7 @@ static ssize_t show_max(struct device *dev, struct device_attribute *attr,
{
struct stts751_priv *priv = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->event_max);
return snprintf(buf, PAGE_SIZE, "%d\n", priv->event_max);
}
static ssize_t set_max(struct device *dev, struct device_attribute *attr,
@ -560,7 +560,7 @@ static ssize_t show_min(struct device *dev, struct device_attribute *attr,
{
struct stts751_priv *priv = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->event_min);
return snprintf(buf, PAGE_SIZE, "%d\n", priv->event_min);
}
static ssize_t set_min(struct device *dev, struct device_attribute *attr,
@ -594,7 +594,7 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr,
{
struct stts751_priv *priv = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE - 1, "%d\n",
return snprintf(buf, PAGE_SIZE, "%d\n",
stts751_intervals[priv->interval]);
}

View file

@ -1676,7 +1676,9 @@ static int w83793_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
static const int watchdog_minors[] = {
WATCHDOG_MINOR, 212, 213, 214, 215
};
struct w83793_data *data;
int i, tmp, val, err;
int files_fan = ARRAY_SIZE(w83793_left_fan) / 7;

View file

@ -91,6 +91,11 @@
#define to_xgene_hwmon_dev(cl) \
container_of(cl, struct xgene_hwmon_dev, mbox_client)
enum xgene_hwmon_version {
XGENE_HWMON_V1 = 0,
XGENE_HWMON_V2 = 1,
};
struct slimpro_resp_msg {
u32 msg;
u32 param1;
@ -609,6 +614,15 @@ static void xgene_hwmon_tx_done(struct mbox_client *cl, void *msg, int ret)
}
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id xgene_hwmon_acpi_match[] = {
{"APMC0D29", XGENE_HWMON_V1},
{"APMC0D8A", XGENE_HWMON_V2},
{},
};
MODULE_DEVICE_TABLE(acpi, xgene_hwmon_acpi_match);
#endif
static int xgene_hwmon_probe(struct platform_device *pdev)
{
struct xgene_hwmon_dev *ctx;
@ -651,6 +665,15 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
}
} else {
struct acpi_pcct_hw_reduced *cppc_ss;
const struct acpi_device_id *acpi_id;
int version;
acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
&pdev->dev);
if (!acpi_id)
return -EINVAL;
version = (int)acpi_id->driver_data;
if (device_property_read_u32(&pdev->dev, "pcc-channel",
&ctx->mbox_idx)) {
@ -693,7 +716,13 @@ static int xgene_hwmon_probe(struct platform_device *pdev)
*/
ctx->comm_base_addr = cppc_ss->base_address;
if (ctx->comm_base_addr) {
ctx->pcc_comm_addr = memremap(ctx->comm_base_addr,
if (version == XGENE_HWMON_V2)
ctx->pcc_comm_addr = (void __force *)ioremap(
ctx->comm_base_addr,
cppc_ss->length);
else
ctx->pcc_comm_addr = memremap(
ctx->comm_base_addr,
cppc_ss->length,
MEMREMAP_WB);
} else {
@ -761,14 +790,6 @@ static int xgene_hwmon_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_ACPI
static const struct acpi_device_id xgene_hwmon_acpi_match[] = {
{"APMC0D29", 0},
{},
};
MODULE_DEVICE_TABLE(acpi, xgene_hwmon_acpi_match);
#endif
static const struct of_device_id xgene_hwmon_of_match[] = {
{.compatible = "apm,xgene-slimpro-hwmon"},
{}