1
0
Fork 0

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
  ...
zero-colors
Linus Torvalds 2017-11-13 08:55:46 -08:00
commit 1e19bded7f
26 changed files with 1130 additions and 402 deletions

View File

@ -0,0 +1,12 @@
Bindings for MAX1619 Temperature Sensor
Required properties:
- compatible : "maxim,max1619"
- reg : I2C address, one of 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, or
0x4d, 0x4e
Example:
temp@4c {
compatible = "maxim,max1619";
reg = <0x4c>;
};

View File

@ -0,0 +1,22 @@
Bindings for the Maxim MAX31785 Intelligent Fan Controller
==========================================================
Reference:
https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf
The Maxim MAX31785 is a PMBus device providing closed-loop, multi-channel fan
management with temperature and remote voltage sensing. Various fan control
features are provided, including PWM frequency control, temperature hysteresis,
dual tachometer measurements, and fan health monitoring.
Required properties:
- compatible : One of "maxim,max31785" or "maxim,max31785a"
- reg : I2C address, one of 0x52, 0x53, 0x54, 0x55.
Example:
fans@52 {
compatible = "maxim,max31785";
reg = <0x52>;
};

View File

@ -71,6 +71,7 @@ isil,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor
isil,isl29030 Intersil ISL29030 Ambient Light and Proximity Sensor
maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
maxim,max6621 PECI-to-I2C translator for PECI-to-SMBus/I2C protocol conversion
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
mc,rv3029c2 Real Time Clock Module with I2C-Bus
mcube,mc3230 mCube 3-axis 8-bit digital accelerometer

View File

@ -0,0 +1,51 @@
Kernel driver max31785
======================
Supported chips:
* Maxim MAX31785, MAX31785A
Prefix: 'max31785' or 'max31785a'
Addresses scanned: -
Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf
Author: Andrew Jeffery <andrew@aj.id.au>
Description
-----------
The Maxim MAX31785 is a PMBus device providing closed-loop, multi-channel fan
management with temperature and remote voltage sensing. Various fan control
features are provided, including PWM frequency control, temperature hysteresis,
dual tachometer measurements, and fan health monitoring.
For dual rotor fan configuration, the MAX31785 exposes the slowest rotor of the
two in the fan[1-4]_input attributes.
Usage Notes
-----------
This driver does not probe for PMBus devices. You will have to instantiate
devices explicitly.
Sysfs attributes
----------------
fan[1-4]_alarm Fan alarm.
fan[1-4]_fault Fan fault.
fan[1-4]_input Fan RPM.
in[1-6]_crit Critical maximum output voltage
in[1-6]_crit_alarm Output voltage critical high alarm
in[1-6]_input Measured output voltage
in[1-6]_label "vout[18-23]"
in[1-6]_lcrit Critical minimum output voltage
in[1-6]_lcrit_alarm Output voltage critical low alarm
in[1-6]_max Maximum output voltage
in[1-6]_max_alarm Output voltage high alarm
in[1-6]_min Minimum output voltage
in[1-6]_min_alarm Output voltage low alarm
temp[1-11]_crit Critical high temperature
temp[1-11]_crit_alarm Chip temperature critical high alarm
temp[1-11]_input Measured temperature
temp[1-11]_max Maximum temperature
temp[1-11]_max_alarm Chip temperature high alarm

View File

@ -42,8 +42,7 @@ chip. These coefficients are used to internally calibrate the signals from the
sensors. Disabling the reload of those coefficients allows saving 10ms for each
measurement and decrease power consumption, while losing on precision.
Some options may be set directly in the sht15_platform_data structure
or via sysfs attributes.
Some options may be set via sysfs attributes.
Notes:
* The regulator supply name is set to "vcc".

View File

@ -29,6 +29,7 @@
#include <linux/platform_data/pcf857x.h>
#include <linux/platform_data/at24.h>
#include <linux/smc91x.h>
#include <linux/gpio/machine.h>
#include <linux/gpio.h>
#include <linux/leds.h>
@ -52,7 +53,6 @@
#include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/mfd/da903x.h>
#include <linux/platform_data/sht15.h>
#include "devices.h"
#include "generic.h"
@ -137,17 +137,18 @@ static unsigned long sg2_im2_unified_pin_config[] __initdata = {
GPIO10_GPIO, /* large basic connector pin 23 */
};
static struct sht15_platform_data platform_data_sht15 = {
.gpio_data = 100,
.gpio_sck = 98,
static struct gpiod_lookup_table sht15_gpiod_table = {
.dev_id = "sht15",
.table = {
/* FIXME: should this have |GPIO_OPEN_DRAIN set? */
GPIO_LOOKUP("gpio-pxa", 100, "data", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("gpio-pxa", 98, "clk", GPIO_ACTIVE_HIGH),
},
};
static struct platform_device sht15 = {
.name = "sht15",
.id = -1,
.dev = {
.platform_data = &platform_data_sht15,
},
};
static struct regulator_consumer_supply stargate2_sensor_3_con[] = {
@ -608,6 +609,7 @@ static void __init imote2_init(void)
imote2_stargate2_init();
gpiod_add_lookup_table(&sht15_gpiod_table);
platform_add_devices(imote2_devices, ARRAY_SIZE(imote2_devices));
i2c_register_board_info(0, imote2_i2c_board_info,
@ -988,6 +990,7 @@ static void __init stargate2_init(void)
imote2_stargate2_init();
gpiod_add_lookup_table(&sht15_gpiod_table);
platform_add_devices(ARRAY_AND_SIZE(stargate2_devices));
i2c_register_board_info(0, ARRAY_AND_SIZE(stargate2_i2c_board_info));

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,

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 <vadimp@mellanox.com>");
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 <andrew@aj.id.au>");
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"},
{}

View File

@ -1,36 +0,0 @@
/*
* include/linux/gpio-fan.h
*
* Platform data structure for GPIO fan driver
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __LINUX_GPIO_FAN_H
#define __LINUX_GPIO_FAN_H
struct gpio_fan_alarm {
unsigned gpio;
unsigned active_low;
};
struct gpio_fan_speed {
int rpm;
int ctrl_val;
};
struct gpio_fan_platform_data {
int num_ctrl;
unsigned *ctrl; /* fan control GPIOs. */
struct gpio_fan_alarm *alarm; /* fan alarm GPIO. */
/*
* Speed conversion array: rpm from/to GPIO bit field.
* This array _must_ be sorted in ascending rpm order.
*/
int num_speed;
struct gpio_fan_speed *speed;
};
#endif /* __LINUX_GPIO_FAN_H */

View File

@ -1,38 +0,0 @@
/*
* sht15.h - support for the SHT15 Temperature and Humidity Sensor
*
* Copyright (c) 2009 Jonathan Cameron
*
* Copyright (c) 2007 Wouter Horre
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* For further information, see the Documentation/hwmon/sht15 file.
*/
#ifndef _PDATA_SHT15_H
#define _PDATA_SHT15_H
/**
* struct sht15_platform_data - sht15 connectivity info
* @gpio_data: no. of gpio to which bidirectional data line is
* connected.
* @gpio_sck: no. of gpio to which the data clock is connected.
* @supply_mv: supply voltage in mv. Overridden by regulator if
* available.
* @checksum: flag to indicate the checksum should be validated.
* @no_otp_reload: flag to indicate no reload from OTP.
* @low_resolution: flag to indicate the temp/humidity resolution to use.
*/
struct sht15_platform_data {
int gpio_data;
int gpio_sck;
int supply_mv;
bool checksum;
bool no_otp_reload;
bool low_resolution;
};
#endif /* _PDATA_SHT15_H */