Commit cdbfbba9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-linus-v4.12' of...

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

Pull hwmon updates from Guenter Roeck:

 - removed twl4030-madc driver

 - added ASPEED PWM/fan driver

 - various minor improvements and fixes in several drivers

* tag 'hwmon-for-linus-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (36 commits)
  hwmon: (twl4030-madc) drop driver
  hwmon: (tmp103) Use SIMPLE_DEV_PM_OPS helper macro
  hwmon: (adt7475) set start bit in probe
  hwmon: (ina209) Handled signed registers
  hwmon: (lm87) Add OF device ID table
  hwmon: (lm87) Remove unused I2C devices driver_data
  drivers: hwmon: Support for ASPEED PWM/Fan tach
  Documentation: dt-bindings: Document bindings for ASPEED AST2400/AST2500 PWM and Fan tach controller device driver
  hwmon: (lm87) Allow channel data to be set from dts file
  Documentation: dtb: lm87: Add hwmon binding documentation
  hwmon: (ads7828) Accept optional parameters from device tree
  hwmon: (dell-smm) Add Dell XPS 15 9560 into DMI list
  hwmon: Constify str parameter of hwmon_ops->read_string
  dt: Add vendor prefix for Sensirion
  hwmon: (tmp421) Add OF device ID table
  hwmon: (tmp103) Add OF device ID table
  hwmon: (tmp102) Add OF device ID table
  hwmon: (stts751) Add OF device ID table
  hwmon: (ucd9200) Add OF device ID table
  hwmon: (ucd9000) Add OF device ID table
  ...
parents 89d1cf89 09d9d827
ads7828 properties
Required properties:
- compatible: Should be one of
ti,ads7828
ti,ads7830
- reg: I2C address
Optional properties:
- ti,differential-input
Set to use the device in differential mode.
- vref-supply
The external reference on the device is set to this regulators output. If it
does not exists the internal reference will be used and output by the ads78xx
on the "external vref" pin.
Example ADS7828 node:
ads7828: ads@48 {
comatible = "ti,ads7828";
reg = <0x48>;
vref-supply = <&vref>;
ti,differential-input;
};
ASPEED AST2400/AST2500 PWM and Fan Tacho controller device driver
The ASPEED PWM controller can support upto 8 PWM outputs. The ASPEED Fan Tacho
controller can support upto 16 Fan tachometer inputs.
There can be upto 8 fans supported. Each fan can have one PWM output and
one/two Fan tach inputs.
Required properties for pwm-tacho node:
- #address-cells : should be 1.
- #size-cells : should be 1.
- reg : address and length of the register set for the device.
- pinctrl-names : a pinctrl state named "default" must be defined.
- pinctrl-0 : phandle referencing pin configuration of the PWM ports.
- compatible : should be "aspeed,ast2400-pwm-tacho" for AST2400 and
"aspeed,ast2500-pwm-tacho" for AST2500.
- clocks : a fixed clock providing input clock frequency(PWM
and Fan Tach clock)
fan subnode format:
===================
Under fan subnode there can upto 8 child nodes, with each child node
representing a fan. If there are 8 fans each fan can have one PWM port and
one/two Fan tach inputs.
Required properties for each child node:
- reg : should specify PWM source port.
integer value in the range 0 to 7 with 0 indicating PWM port A and
7 indicating PWM port H.
- aspeed,fan-tach-ch : should specify the Fan tach input channel.
integer value in the range 0 through 15, with 0 indicating
Fan tach channel 0 and 15 indicating Fan tach channel 15.
Atleast one Fan tach input channel is required.
Examples:
pwm_tacho_fixed_clk: fixedclk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <24000000>;
};
pwm_tacho: pwmtachocontroller@1e786000 {
#address-cells = <1>;
#size-cells = <1>;
reg = <0x1E786000 0x1000>;
compatible = "aspeed,ast2500-pwm-tacho";
clocks = <&pwm_tacho_fixed_clk>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm0_default &pinctrl_pwm1_default>;
fan@0 {
reg = <0x00>;
aspeed,fan-tach-ch = /bits/ 8 <0x00>;
};
fan@1 {
reg = <0x01>;
aspeed,fan-tach-ch = /bits/ 8 <0x01 0x02>;
};
};
*LM87 hwmon sensor.
Required properties:
- compatible: Should be
"ti,lm87"
- reg: I2C address
optional properties:
- has-temp3: This configures pins 18 and 19 to be used as a second
remote temperature sensing channel. By default the pins
are configured as voltage input pins in0 and in5.
- has-in6: When set, pin 5 is configured to be used as voltage input
in6. Otherwise the pin is set as FAN1 input.
- has-in7: When set, pin 6 is configured to be used as voltage input
in7. Otherwise the pin is set as FAN2 input.
- vcc-supply: a Phandle for the regulator supplying power, can be
cofigured to measure 5.0V power supply. Default is 3.3V.
Example:
lm87@2e {
compatible = "ti,lm87";
reg = <0x2e>;
has-temp3;
vcc-supply = <&reg_5v0>;
};
......@@ -265,6 +265,7 @@ sbs Smart Battery System
schindler Schindler
seagate Seagate Technology PLC
semtech Semtech Corporation
sensirion Sensirion AG
sgx SGX Sensortech
sharp Sharp Corporation
si-en Si-En Technology Ltd.
......
Kernel driver aspeed-pwm-tacho
==============================
Supported chips:
ASPEED AST2400/2500
Authors:
<jaghu@google.com>
Description:
------------
This driver implements support for ASPEED AST2400/2500 PWM and Fan Tacho
controller. The PWM controller supports upto 8 PWM outputs. The Fan tacho
controller supports up to 16 tachometer inputs.
The driver provides the following sensor accesses in sysfs:
fanX_input ro provide current fan rotation value in RPM as reported
by the fan to the device.
pwmX rw get or set PWM fan control value. This is an integer
value between 0(off) and 255(full speed).
......@@ -2,7 +2,7 @@ Kernel driver tc654
===================
Supported chips:
* Microship TC654 and TC655
* Microchip TC654 and TC655
Prefix: 'tc654'
Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/20001734C.pdf
......
......@@ -341,6 +341,15 @@ config SENSORS_ASB100
This driver can also be built as a module. If so, the module
will be called asb100.
config SENSORS_ASPEED
tristate "ASPEED AST2400/AST2500 PWM and Fan tach driver"
help
This driver provides support for ASPEED AST2400/AST2500 PWM
and Fan Tacho controllers.
This driver can also be built as a module. If so, the module
will be called aspeed_pwm_tacho.
config SENSORS_ATXP1
tristate "Attansic ATXP1 VID controller"
depends on I2C
......@@ -1643,16 +1652,6 @@ config SENSORS_TMP421
This driver can also be built as a module. If so, the module
will be called tmp421.
config SENSORS_TWL4030_MADC
tristate "Texas Instruments TWL4030 MADC Hwmon"
depends on TWL4030_MADC
help
If you say yes here you get hwmon support for triton
TWL4030-MADC.
This driver can also be built as a module. If so it will be called
twl4030-madc-hwmon.
config SENSORS_VEXPRESS
tristate "Versatile Express"
depends on VEXPRESS_CONFIG
......
......@@ -46,6 +46,7 @@ obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o
obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
obj-$(CONFIG_SENSORS_ASPEED) += aspeed-pwm-tacho.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
......@@ -157,7 +158,6 @@ obj-$(CONFIG_SENSORS_TMP103) += tmp103.o
obj-$(CONFIG_SENSORS_TMP108) += tmp108.o
obj-$(CONFIG_SENSORS_TMP401) += tmp401.o
obj-$(CONFIG_SENSORS_TMP421) += tmp421.o
obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o
obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o
obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
......
......@@ -217,9 +217,16 @@ static const struct i2c_device_id ad7414_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ad7414_id);
static const struct of_device_id ad7414_of_match[] = {
{ .compatible = "ad,ad7414" },
{ },
};
MODULE_DEVICE_TABLE(of, ad7414_of_match);
static struct i2c_driver ad7414_driver = {
.driver = {
.name = "ad7414",
.of_match_table = of_match_ptr(ad7414_of_match),
},
.probe = ad7414_probe,
.id_table = ad7414_id,
......
......@@ -546,10 +546,17 @@ static const struct i2c_device_id adc128_id[] = {
};
MODULE_DEVICE_TABLE(i2c, adc128_id);
static const struct of_device_id adc128_of_match[] = {
{ .compatible = "ti,adc128d818" },
{ },
};
MODULE_DEVICE_TABLE(of, adc128_of_match);
static struct i2c_driver adc128_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "adc128d818",
.of_match_table = of_match_ptr(adc128_of_match),
},
.probe = adc128_probe,
.remove = adc128_remove,
......
......@@ -31,6 +31,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/i2c/ads1015.h>
......@@ -268,7 +269,12 @@ static int ads1015_probe(struct i2c_client *client,
GFP_KERNEL);
if (!data)
return -ENOMEM;
data->id = id->driver_data;
if (client->dev.of_node)
data->id = (enum ads1015_chips)
of_device_get_match_data(&client->dev);
else
data->id = id->driver_data;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
......@@ -303,9 +309,23 @@ static const struct i2c_device_id ads1015_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ads1015_id);
static const struct of_device_id ads1015_of_match[] = {
{
.compatible = "ti,ads1015",
.data = (void *)ads1015
},
{
.compatible = "ti,ads1115",
.data = (void *)ads1115
},
{ },
};
MODULE_DEVICE_TABLE(of, ads1015_of_match);
static struct i2c_driver ads1015_driver = {
.driver = {
.name = "ads1015",
.of_match_table = of_match_ptr(ads1015_of_match),
},
.probe = ads1015_probe,
.remove = ads1015_remove,
......
......@@ -31,9 +31,11 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_data/ads7828.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
/* The ADS7828 registers */
#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
......@@ -118,9 +120,12 @@ static int ads7828_probe(struct i2c_client *client,
struct ads7828_data *data;
struct device *hwmon_dev;
unsigned int vref_mv = ADS7828_INT_VREF_MV;
unsigned int vref_uv;
bool diff_input = false;
bool ext_vref = false;
unsigned int regval;
enum ads7828_chips chip;
struct regulator *reg;
data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
if (!data)
......@@ -131,14 +136,32 @@ static int ads7828_probe(struct i2c_client *client,
ext_vref = pdata->ext_vref;
if (ext_vref && pdata->vref_mv)
vref_mv = pdata->vref_mv;
} else if (dev->of_node) {
diff_input = of_property_read_bool(dev->of_node,
"ti,differential-input");
reg = devm_regulator_get_optional(dev, "vref");
if (!IS_ERR(reg)) {
vref_uv = regulator_get_voltage(reg);
vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000);
if (vref_mv < ADS7828_EXT_VREF_MV_MIN ||
vref_mv > ADS7828_EXT_VREF_MV_MAX)
return -EINVAL;
ext_vref = true;
}
}
if (client->dev.of_node)
chip = (enum ads7828_chips)
of_device_get_match_data(&client->dev);
else
chip = id->driver_data;
/* Bound Vref with min/max values */
vref_mv = clamp_val(vref_mv, ADS7828_EXT_VREF_MV_MIN,
ADS7828_EXT_VREF_MV_MAX);
/* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */
if (id->driver_data == ads7828) {
if (chip == ads7828) {
data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 4096);
data->regmap = devm_regmap_init_i2c(client,
&ads2828_regmap_config);
......@@ -177,9 +200,23 @@ static const struct i2c_device_id ads7828_device_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, ads7828_device_ids);
static const struct of_device_id ads7828_of_match[] = {
{
.compatible = "ti,ads7828",
.data = (void *)ads7828
},
{
.compatible = "ti,ads7830",
.data = (void *)ads7830
},
{ },
};
MODULE_DEVICE_TABLE(of, ads7828_of_match);
static struct i2c_driver ads7828_driver = {
.driver = {
.name = "ads7828",
.of_match_table = of_match_ptr(ads7828_of_match),
},
.id_table = ads7828_device_ids,
......
......@@ -13,6 +13,7 @@
*/
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
......@@ -58,6 +59,8 @@
#define REG_VENDID 0x3E
#define REG_DEVID2 0x3F
#define REG_CONFIG1 0x40
#define REG_STATUS1 0x41
#define REG_STATUS2 0x42
......@@ -161,6 +164,27 @@ static const struct i2c_device_id adt7475_id[] = {
};
MODULE_DEVICE_TABLE(i2c, adt7475_id);
static const struct of_device_id adt7475_of_match[] = {
{
.compatible = "adi,adt7473",
.data = (void *)adt7473
},
{
.compatible = "adi,adt7475",
.data = (void *)adt7475
},
{
.compatible = "adi,adt7476",
.data = (void *)adt7476
},
{
.compatible = "adi,adt7490",
.data = (void *)adt7490
},
{ },
};
MODULE_DEVICE_TABLE(of, adt7475_of_match);
struct adt7475_data {
struct device *hwmon_dev;
struct mutex lock;
......@@ -1250,6 +1274,7 @@ static void adt7475_remove_files(struct i2c_client *client,
static int adt7475_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
enum chips chip;
static const char * const names[] = {
[adt7473] = "ADT7473",
[adt7475] = "ADT7475",
......@@ -1268,8 +1293,13 @@ static int adt7475_probe(struct i2c_client *client,
mutex_init(&data->lock);
i2c_set_clientdata(client, data);
if (client->dev.of_node)
chip = (enum chips)of_device_get_match_data(&client->dev);
else
chip = id->driver_data;
/* Initialize device-specific values */
switch (id->driver_data) {
switch (chip) {
case adt7476:
data->has_voltage = 0x0e; /* in1 to in3 */
revision = adt7475_read(REG_DEVID2) & 0x07;
......@@ -1343,6 +1373,17 @@ static int adt7475_probe(struct i2c_client *client,
for (i = 0; i < ADT7475_PWM_COUNT; i++)
adt7475_read_pwm(client, i);
/* Start monitoring */
switch (chip) {
case adt7475:
case adt7476:
i2c_smbus_write_byte_data(client, REG_CONFIG1,
adt7475_read(REG_CONFIG1) | 0x01);
break;
default:
break;
}
ret = sysfs_create_group(&client->dev.kobj, &adt7475_attr_group);
if (ret)
return ret;
......@@ -1428,6 +1469,7 @@ static struct i2c_driver adt7475_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "adt7475",
.of_match_table = of_match_ptr(adt7475_of_match),
},
.probe = adt7475_probe,
.remove = adt7475_remove,
......
/*
* Copyright (c) 2016 Google, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 or later as
* published by the Free Software Foundation.
*/
#include <linux/clk.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/platform_device.h>
#include <linux/sysfs.h>
#include <linux/regmap.h>
/* ASPEED PWM & FAN Tach Register Definition */
#define ASPEED_PTCR_CTRL 0x00
#define ASPEED_PTCR_CLK_CTRL 0x04
#define ASPEED_PTCR_DUTY0_CTRL 0x08
#define ASPEED_PTCR_DUTY1_CTRL 0x0c
#define ASPEED_PTCR_TYPEM_CTRL 0x10
#define ASPEED_PTCR_TYPEM_CTRL1 0x14
#define ASPEED_PTCR_TYPEN_CTRL 0x18
#define ASPEED_PTCR_TYPEN_CTRL1 0x1c
#define ASPEED_PTCR_TACH_SOURCE 0x20
#define ASPEED_PTCR_TRIGGER 0x28
#define ASPEED_PTCR_RESULT 0x2c
#define ASPEED_PTCR_INTR_CTRL 0x30
#define ASPEED_PTCR_INTR_STS 0x34
#define ASPEED_PTCR_TYPEM_LIMIT 0x38
#define ASPEED_PTCR_TYPEN_LIMIT 0x3C
#define ASPEED_PTCR_CTRL_EXT 0x40
#define ASPEED_PTCR_CLK_CTRL_EXT 0x44
#define ASPEED_PTCR_DUTY2_CTRL 0x48
#define ASPEED_PTCR_DUTY3_CTRL 0x4c
#define ASPEED_PTCR_TYPEO_CTRL 0x50
#define ASPEED_PTCR_TYPEO_CTRL1 0x54
#define ASPEED_PTCR_TACH_SOURCE_EXT 0x60
#define ASPEED_PTCR_TYPEO_LIMIT 0x78
/* ASPEED_PTCR_CTRL : 0x00 - General Control Register */
#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1 15
#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2 6
#define ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK (BIT(7) | BIT(15))
#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1 14
#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2 5
#define ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK (BIT(6) | BIT(14))
#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1 13
#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2 4
#define ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK (BIT(5) | BIT(13))
#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1 12
#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2 3
#define ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK (BIT(4) | BIT(12))
#define ASPEED_PTCR_CTRL_FAN_NUM_EN(x) BIT(16 + (x))
#define ASPEED_PTCR_CTRL_PWMD_EN BIT(11)
#define ASPEED_PTCR_CTRL_PWMC_EN BIT(10)
#define ASPEED_PTCR_CTRL_PWMB_EN BIT(9)
#define ASPEED_PTCR_CTRL_PWMA_EN BIT(8)
#define ASPEED_PTCR_CTRL_CLK_SRC BIT(1)
#define ASPEED_PTCR_CTRL_CLK_EN BIT(0)
/* ASPEED_PTCR_CLK_CTRL : 0x04 - Clock Control Register */
/* TYPE N */
#define ASPEED_PTCR_CLK_CTRL_TYPEN_MASK GENMASK(31, 16)
#define ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT 24
#define ASPEED_PTCR_CLK_CTRL_TYPEN_H 20
#define ASPEED_PTCR_CLK_CTRL_TYPEN_L 16
/* TYPE M */
#define ASPEED_PTCR_CLK_CTRL_TYPEM_MASK GENMASK(15, 0)
#define ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT 8
#define ASPEED_PTCR_CLK_CTRL_TYPEM_H 4
#define ASPEED_PTCR_CLK_CTRL_TYPEM_L 0
/*
* ASPEED_PTCR_DUTY_CTRL/1/2/3 : 0x08/0x0C/0x48/0x4C - PWM-FAN duty control
* 0/1/2/3 register
*/
#define DUTY_CTRL_PWM2_FALL_POINT 24
#define DUTY_CTRL_PWM2_RISE_POINT 16
#define DUTY_CTRL_PWM2_RISE_FALL_MASK GENMASK(31, 16)
#define DUTY_CTRL_PWM1_FALL_POINT 8
#define DUTY_CTRL_PWM1_RISE_POINT 0
#define DUTY_CTRL_PWM1_RISE_FALL_MASK GENMASK(15, 0)
/* ASPEED_PTCR_TYPEM_CTRL : 0x10/0x18/0x50 - Type M/N/O Ctrl 0 Register */
#define TYPE_CTRL_FAN_MASK (GENMASK(5, 1) | GENMASK(31, 16))
#define TYPE_CTRL_FAN1_MASK GENMASK(31, 0)
#define TYPE_CTRL_FAN_PERIOD 16
#define TYPE_CTRL_FAN_MODE 4
#define TYPE_CTRL_FAN_DIVISION 1
#define TYPE_CTRL_FAN_TYPE_EN 1
/* ASPEED_PTCR_TACH_SOURCE : 0x20/0x60 - Tach Source Register */
/* bit [0,1] at 0x20, bit [2] at 0x60 */
#define TACH_PWM_SOURCE_BIT01(x) ((x) * 2)
#define TACH_PWM_SOURCE_BIT2(x) ((x) * 2)
#define TACH_PWM_SOURCE_MASK_BIT01(x) (0x3 << ((x) * 2))
#define TACH_PWM_SOURCE_MASK_BIT2(x) BIT((x) * 2)
/* ASPEED_PTCR_RESULT : 0x2c - Result Register */
#define RESULT_STATUS_MASK BIT(31)
#define RESULT_VALUE_MASK 0xfffff
/* ASPEED_PTCR_CTRL_EXT : 0x40 - General Control Extension #1 Register */
#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1 15
#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2 6
#define ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK (BIT(7) | BIT(15))
#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1 14
#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2 5
#define ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK (BIT(6) | BIT(14))
#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1 13
#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2 4
#define ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK (BIT(5) | BIT(13))
#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1 12
#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2 3
#define ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK (BIT(4) | BIT(12))
#define ASPEED_PTCR_CTRL_PWMH_EN BIT(11)
#define ASPEED_PTCR_CTRL_PWMG_EN BIT(10)
#define ASPEED_PTCR_CTRL_PWMF_EN BIT(9)
#define ASPEED_PTCR_CTRL_PWME_EN BIT(8)
/* ASPEED_PTCR_CLK_EXT_CTRL : 0x44 - Clock Control Extension #1 Register */
/* TYPE O */
#define ASPEED_PTCR_CLK_CTRL_TYPEO_MASK GENMASK(15, 0)
#define ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT 8
#define ASPEED_PTCR_CLK_CTRL_TYPEO_H 4
#define ASPEED_PTCR_CLK_CTRL_TYPEO_L 0
#define PWM_MAX 255
#define M_PWM_DIV_H 0x00
#define M_PWM_DIV_L 0x05
#define M_PWM_PERIOD 0x5F
#define M_TACH_CLK_DIV 0x00
#define M_TACH_MODE 0x00
#define M_TACH_UNIT 0x1000
#define INIT_FAN_CTRL 0xFF
struct aspeed_pwm_tacho_data {
struct regmap *regmap;
unsigned long clk_freq;
bool pwm_present[8];
bool fan_tach_present[16];
u8 type_pwm_clock_unit[3];
u8 type_pwm_clock_division_h[3];
u8 type_pwm_clock_division_l[3];
u8 type_fan_tach_clock_division[3];
u16 type_fan_tach_unit[3];
u8 pwm_port_type[8];
u8 pwm_port_fan_ctrl[8];
u8 fan_tach_ch_source[16];
const struct attribute_group *groups[3];
};
enum type { TYPEM, TYPEN, TYPEO };
struct type_params {
u32 l_value;
u32 h_value;
u32 unit_value;
u32 clk_ctrl_mask;
u32 clk_ctrl_reg;
u32 ctrl_reg;
u32 ctrl_reg1;
};
static const struct type_params type_params[] = {
[TYPEM] = {
.l_value = ASPEED_PTCR_CLK_CTRL_TYPEM_L,
.h_value = ASPEED_PTCR_CLK_CTRL_TYPEM_H,
.unit_value = ASPEED_PTCR_CLK_CTRL_TYPEM_UNIT,
.clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEM_MASK,
.clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL,
.ctrl_reg = ASPEED_PTCR_TYPEM_CTRL,
.ctrl_reg1 = ASPEED_PTCR_TYPEM_CTRL1,
},
[TYPEN] = {
.l_value = ASPEED_PTCR_CLK_CTRL_TYPEN_L,
.h_value = ASPEED_PTCR_CLK_CTRL_TYPEN_H,
.unit_value = ASPEED_PTCR_CLK_CTRL_TYPEN_UNIT,
.clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEN_MASK,
.clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL,
.ctrl_reg = ASPEED_PTCR_TYPEN_CTRL,
.ctrl_reg1 = ASPEED_PTCR_TYPEN_CTRL1,
},
[TYPEO] = {
.l_value = ASPEED_PTCR_CLK_CTRL_TYPEO_L,
.h_value = ASPEED_PTCR_CLK_CTRL_TYPEO_H,
.unit_value = ASPEED_PTCR_CLK_CTRL_TYPEO_UNIT,
.clk_ctrl_mask = ASPEED_PTCR_CLK_CTRL_TYPEO_MASK,
.clk_ctrl_reg = ASPEED_PTCR_CLK_CTRL_EXT,
.ctrl_reg = ASPEED_PTCR_TYPEO_CTRL,
.ctrl_reg1 = ASPEED_PTCR_TYPEO_CTRL1,
}
};
enum pwm_port { PWMA, PWMB, PWMC, PWMD, PWME, PWMF, PWMG, PWMH };
struct pwm_port_params {
u32 pwm_en;
u32 ctrl_reg;
u32 type_part1;
u32 type_part2;
u32 type_mask;
u32 duty_ctrl_rise_point;
u32 duty_ctrl_fall_point;
u32 duty_ctrl_reg;
u32 duty_ctrl_rise_fall_mask;
};
static const struct pwm_port_params pwm_port_params[] = {
[PWMA] = {
.pwm_en = ASPEED_PTCR_CTRL_PWMA_EN,
.ctrl_reg = ASPEED_PTCR_CTRL,
.type_part1 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART1,
.type_part2 = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_PART2,
.type_mask = ASPEED_PTCR_CTRL_SET_PWMA_TYPE_MASK,
.duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
.duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
.duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL,
.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
},
[PWMB] = {
.pwm_en = ASPEED_PTCR_CTRL_PWMB_EN,
.ctrl_reg = ASPEED_PTCR_CTRL,
.type_part1 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART1,
.type_part2 = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_PART2,
.type_mask = ASPEED_PTCR_CTRL_SET_PWMB_TYPE_MASK,
.duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
.duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
.duty_ctrl_reg = ASPEED_PTCR_DUTY0_CTRL,
.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
},
[PWMC] = {
.pwm_en = ASPEED_PTCR_CTRL_PWMC_EN,
.ctrl_reg = ASPEED_PTCR_CTRL,
.type_part1 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART1,
.type_part2 = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_PART2,
.type_mask = ASPEED_PTCR_CTRL_SET_PWMC_TYPE_MASK,
.duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
.duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
.duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL,
.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
},
[PWMD] = {
.pwm_en = ASPEED_PTCR_CTRL_PWMD_EN,
.ctrl_reg = ASPEED_PTCR_CTRL,
.type_part1 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART1,
.type_part2 = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_PART2,
.type_mask = ASPEED_PTCR_CTRL_SET_PWMD_TYPE_MASK,
.duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
.duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
.duty_ctrl_reg = ASPEED_PTCR_DUTY1_CTRL,
.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
},
[PWME] = {
.pwm_en = ASPEED_PTCR_CTRL_PWME_EN,
.ctrl_reg = ASPEED_PTCR_CTRL_EXT,
.type_part1 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART1,
.type_part2 = ASPEED_PTCR_CTRL_SET_PWME_TYPE_PART2,
.type_mask = ASPEED_PTCR_CTRL_SET_PWME_TYPE_MASK,
.duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
.duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
.duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL,
.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
},
[PWMF] = {
.pwm_en = ASPEED_PTCR_CTRL_PWMF_EN,
.ctrl_reg = ASPEED_PTCR_CTRL_EXT,
.type_part1 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART1,
.type_part2 = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_PART2,
.type_mask = ASPEED_PTCR_CTRL_SET_PWMF_TYPE_MASK,
.duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
.duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
.duty_ctrl_reg = ASPEED_PTCR_DUTY2_CTRL,
.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
},
[PWMG] = {
.pwm_en = ASPEED_PTCR_CTRL_PWMG_EN,
.ctrl_reg = ASPEED_PTCR_CTRL_EXT,
.type_part1 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART1,
.type_part2 = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_PART2,
.type_mask = ASPEED_PTCR_CTRL_SET_PWMG_TYPE_MASK,
.duty_ctrl_rise_point = DUTY_CTRL_PWM1_RISE_POINT,
.duty_ctrl_fall_point = DUTY_CTRL_PWM1_FALL_POINT,
.duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL,
.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM1_RISE_FALL_MASK,
},
[PWMH] = {
.pwm_en = ASPEED_PTCR_CTRL_PWMH_EN,
.ctrl_reg = ASPEED_PTCR_CTRL_EXT,
.type_part1 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART1,
.type_part2 = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_PART2,
.type_mask = ASPEED_PTCR_CTRL_SET_PWMH_TYPE_MASK,
.duty_ctrl_rise_point = DUTY_CTRL_PWM2_RISE_POINT,
.duty_ctrl_fall_point = DUTY_CTRL_PWM2_FALL_POINT,
.duty_ctrl_reg = ASPEED_PTCR_DUTY3_CTRL,
.duty_ctrl_rise_fall_mask = DUTY_CTRL_PWM2_RISE_FALL_MASK,
}
};
static int regmap_aspeed_pwm_tacho_reg_write(void *context, unsigned int reg,
unsigned int val)
{
void __iomem *regs = (void __iomem *)context;
writel(val, regs + reg);
return 0;
}
static int regmap_aspeed_pwm_tacho_reg_read(void *context, unsigned int reg,
unsigned int *val)
{
void __iomem *regs = (void __iomem *)context;
*val = readl(regs + reg);
return 0;
}
static const struct regmap_config aspeed_pwm_tacho_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = ASPEED_PTCR_TYPEO_LIMIT,
.reg_write = regmap_aspeed_pwm_tacho_reg_write,
.reg_read = regmap_aspeed_pwm_tacho_reg_read,
.fast_io = true,
};
static void aspeed_set_clock_enable(struct regmap *regmap, bool val)
{
regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
ASPEED_PTCR_CTRL_CLK_EN,
val ? ASPEED_PTCR_CTRL_CLK_EN : 0);
}
static void aspeed_set_clock_source(struct regmap *regmap, int val)
{
regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
ASPEED_PTCR_CTRL_CLK_SRC,
val ? ASPEED_PTCR_CTRL_CLK_SRC : 0);
}
static void aspeed_set_pwm_clock_values(struct regmap *regmap, u8 type,
u8 div_high, u8 div_low, u8 unit)
{
u32 reg_value = ((div_high << type_params[type].h_value) |
(div_low << type_params[type].l_value) |
(unit << type_params[type].unit_value));
regmap_update_bits(regmap, type_params[type].clk_ctrl_reg,
type_params[type].clk_ctrl_mask, reg_value);
}
static void aspeed_set_pwm_port_enable(struct regmap *regmap, u8 pwm_port,
bool enable)
{
regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg,
pwm_port_params[pwm_port].pwm_en,
enable ? pwm_port_params[pwm_port].pwm_en : 0);
}
static void aspeed_set_pwm_port_type(struct regmap *regmap,
u8 pwm_port, u8 type)
{
u32 reg_value = (type & 0x1) << pwm_port_params[pwm_port].type_part1;
reg_value |= (type & 0x2) << pwm_port_params[pwm_port].type_part2;
regmap_update_bits(regmap, pwm_port_params[pwm_port].ctrl_reg,
pwm_port_params[pwm_port].type_mask, reg_value);
}
static void aspeed_set_pwm_port_duty_rising_falling(struct regmap *regmap,
u8 pwm_port, u8 rising,
u8 falling)
{
u32 reg_value = (rising <<
pwm_port_params[pwm_port].duty_ctrl_rise_point);
reg_value |= (falling <<
pwm_port_params[pwm_port].duty_ctrl_fall_point);
regmap_update_bits(regmap, pwm_port_params[pwm_port].duty_ctrl_reg,
pwm_port_params[pwm_port].duty_ctrl_rise_fall_mask,
reg_value);
}
static void aspeed_set_tacho_type_enable(struct regmap *regmap, u8 type,
bool enable)
{
regmap_update_bits(regmap, type_params[type].ctrl_reg,
TYPE_CTRL_FAN_TYPE_EN,
enable ? TYPE_CTRL_FAN_TYPE_EN : 0);
}
static void aspeed_set_tacho_type_values(struct regmap *regmap, u8 type,
u8 mode, u16 unit, u8 division)
{
u32 reg_value = ((mode << TYPE_CTRL_FAN_MODE) |
(unit << TYPE_CTRL_FAN_PERIOD) |
(division << TYPE_CTRL_FAN_DIVISION));
regmap_update_bits(regmap, type_params[type].ctrl_reg,
TYPE_CTRL_FAN_MASK, reg_value);
regmap_update_bits(regmap, type_params[type].ctrl_reg1,
TYPE_CTRL_FAN1_MASK, unit << 16);
}
static void aspeed_set_fan_tach_ch_enable(struct regmap *regmap, u8 fan_tach_ch,
bool enable)
{
regmap_update_bits(regmap, ASPEED_PTCR_CTRL,
ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch),
enable ?
ASPEED_PTCR_CTRL_FAN_NUM_EN(fan_tach_ch) : 0);
}
static void aspeed_set_fan_tach_ch_source(struct regmap *regmap, u8 fan_tach_ch,
u8 fan_tach_ch_source)
{
u32 reg_value1 = ((fan_tach_ch_source & 0x3) <<
TACH_PWM_SOURCE_BIT01(fan_tach_ch));
u32 reg_value2 = (((fan_tach_ch_source & 0x4) >> 2) <<
TACH_PWM_SOURCE_BIT2(fan_tach_ch));
regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE,
TACH_PWM_SOURCE_MASK_BIT01(fan_tach_ch),
reg_value1);
regmap_update_bits(regmap, ASPEED_PTCR_TACH_SOURCE_EXT,
TACH_PWM_SOURCE_MASK_BIT2(fan_tach_ch),
reg_value2);
}
static void aspeed_set_pwm_port_fan_ctrl(struct aspeed_pwm_tacho_data *priv,
u8 index, u8 fan_ctrl)
{
u16 period, dc_time_on;
period = priv->type_pwm_clock_unit[priv->pwm_port_type[index]];
period += 1;
dc_time_on = (fan_ctrl * period) / PWM_MAX;
if (dc_time_on == 0) {
aspeed_set_pwm_port_enable(priv->regmap, index, false);
} else {
if (dc_time_on == period)
dc_time_on = 0;
aspeed_set_pwm_port_duty_rising_falling(priv->regmap, index, 0,
dc_time_on);
aspeed_set_pwm_port_enable(priv->regmap, index, true);
}
}
static u32 aspeed_get_fan_tach_ch_measure_period(struct aspeed_pwm_tacho_data
*priv, u8 type)
{
u32 clk;
u16 tacho_unit;
u8 clk_unit, div_h, div_l, tacho_div;
clk = priv->clk_freq;
clk_unit = priv->type_pwm_clock_unit[type];
div_h = priv->type_pwm_clock_division_h[type];
div_h = 0x1 << div_h;
div_l = priv->type_pwm_clock_division_l[type];
if (div_l == 0)
div_l = 1;
else
div_l = div_l * 2;
tacho_unit = priv->type_fan_tach_unit[type];
tacho_div = priv->type_fan_tach_clock_division[type];
tacho_div = 0x4 << (tacho_div * 2);
return clk / (clk_unit * div_h * div_l * tacho_div * tacho_unit);
}
static u32 aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv,
u8 fan_tach_ch)
{
u32 raw_data, tach_div, clk_source, sec, val;
u8 fan_tach_ch_source, type;
regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0);
regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch);
fan_tach_ch_source = priv->fan_tach_ch_source[fan_tach_ch];
type = priv->pwm_port_type[fan_tach_ch_source];
sec = (1000 / aspeed_get_fan_tach_ch_measure_period(priv, type));
msleep(sec);
regmap_read(priv->regmap, ASPEED_PTCR_RESULT, &val);
raw_data = val & RESULT_VALUE_MASK;
tach_div = priv->type_fan_tach_clock_division[type];
tach_div = 0x4 << (tach_div * 2);
clk_source = priv->clk_freq;
if (raw_data == 0)
return 0;
return (clk_source * 60) / (2 * raw_data * tach_div);
}
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int index = sensor_attr->index;
int ret;
struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
long fan_ctrl;
ret = kstrtol(buf, 10, &fan_ctrl);
if (ret != 0)
return ret;
if (fan_ctrl < 0 || fan_ctrl > PWM_MAX)
return -EINVAL;
if (priv->pwm_port_fan_ctrl[index] == fan_ctrl)
return count;
priv->pwm_port_fan_ctrl[index] = fan_ctrl;
aspeed_set_pwm_port_fan_ctrl(priv, index, fan_ctrl);
return count;
}
static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int index = sensor_attr->index;
struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", priv->pwm_port_fan_ctrl[index]);
}
static ssize_t show_rpm(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int index = sensor_attr->index;
u32 rpm;
struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
rpm = aspeed_get_fan_tach_ch_rpm(priv, index);
return sprintf(buf, "%u\n", rpm);
}
static umode_t pwm_is_visible(struct kobject *kobj,
struct attribute *a, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
if (!priv->pwm_present[index])
return 0;
return a->mode;
}
static umode_t fan_dev_is_visible(struct kobject *kobj,
struct attribute *a, int index)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct aspeed_pwm_tacho_data *priv = dev_get_drvdata(dev);
if (!priv->fan_tach_present[index])
return 0;
return a->mode;
}
static SENSOR_DEVICE_ATTR(pwm0, 0644,
show_pwm, set_pwm, 0);
static SENSOR_DEVICE_ATTR(pwm1, 0644,
show_pwm, set_pwm, 1);
static SENSOR_DEVICE_ATTR(pwm2, 0644,
show_pwm, set_pwm, 2);
static SENSOR_DEVICE_ATTR(pwm3, 0644,
show_pwm, set_pwm, 3);
static SENSOR_DEVICE_ATTR(pwm4, 0644,
show_pwm, set_pwm, 4);
static SENSOR_DEVICE_ATTR(pwm5, 0644,
show_pwm, set_pwm, 5);
static SENSOR_DEVICE_ATTR(pwm6, 0644,
show_pwm, set_pwm, 6);
static SENSOR_DEVICE_ATTR(pwm7, 0644,
show_pwm, set_pwm, 7);
static struct attribute *pwm_dev_attrs[] = {
&sensor_dev_attr_pwm0.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_pwm2.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr,
&sensor_dev_attr_pwm4.dev_attr.attr,
&sensor_dev_attr_pwm5.dev_attr.attr,
&sensor_dev_attr_pwm6.dev_attr.attr,
&sensor_dev_attr_pwm7.dev_attr.attr,
NULL,
};
static const struct attribute_group pwm_dev_group = {
.attrs = pwm_dev_attrs,
.is_visible = pwm_is_visible,
};
static SENSOR_DEVICE_ATTR(fan0_input, 0444,
show_rpm, NULL, 0);
static SENSOR_DEVICE_ATTR(fan1_input, 0444,
show_rpm, NULL, 1);
static SENSOR_DEVICE_ATTR(fan2_input, 0444,
show_rpm, NULL, 2);
static SENSOR_DEVICE_ATTR(fan3_input, 0444,
show_rpm, NULL, 3);
static SENSOR_DEVICE_ATTR(fan4_input, 0444,
show_rpm, NULL, 4);
static SENSOR_DEVICE_ATTR(fan5_input, 0444,
show_rpm, NULL, 5);
static SENSOR_DEVICE_ATTR(fan6_input, 0444,
show_rpm, NULL, 6);
static SENSOR_DEVICE_ATTR(fan7_input, 0444,
show_rpm, NULL, 7);
static SENSOR_DEVICE_ATTR(fan8_input, 0444,
show_rpm, NULL, 8);
static SENSOR_DEVICE_ATTR(fan9_input, 0444,
show_rpm, NULL, 9);
static SENSOR_DEVICE_ATTR(fan10_input, 0444,
show_rpm, NULL, 10);
static SENSOR_DEVICE_ATTR(fan11_input, 0444,
show_rpm, NULL, 11);
static SENSOR_DEVICE_ATTR(fan12_input, 0444,
show_rpm, NULL, 12);
static SENSOR_DEVICE_ATTR(fan13_input, 0444,
show_rpm, NULL, 13);
static SENSOR_DEVICE_ATTR(fan14_input, 0444,
show_rpm, NULL, 14);
static SENSOR_DEVICE_ATTR(fan15_input, 0444,
show_rpm, NULL, 15);
static struct attribute *fan_dev_attrs[] = {
&sensor_dev_attr_fan0_input.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan4_input.dev_attr.attr,
&sensor_dev_attr_fan5_input.dev_attr.attr,
&sensor_dev_attr_fan6_input.dev_attr.attr,
&sensor_dev_attr_fan7_input.dev_attr.attr,
&sensor_dev_attr_fan8_input.dev_attr.attr,
&sensor_dev_attr_fan9_input.dev_attr.attr,
&sensor_dev_attr_fan10_input.dev_attr.attr,
&sensor_dev_attr_fan11_input.dev_attr.attr,
&sensor_dev_attr_fan12_input.dev_attr.attr,
&sensor_dev_attr_fan13_input.dev_attr.attr,
&sensor_dev_attr_fan14_input.dev_attr.attr,
&sensor_dev_attr_fan15_input.dev_attr.attr,
NULL
};
static const struct attribute_group fan_dev_group = {
.attrs = fan_dev_attrs,
.is_visible = fan_dev_is_visible,
};
/*
* The clock type is type M :
* The PWM frequency = 24MHz / (type M clock division L bit *
* type M clock division H bit * (type M PWM period bit + 1))
*/
static void aspeed_create_type(struct aspeed_pwm_tacho_data *priv)
{
priv->type_pwm_clock_division_h[TYPEM] = M_PWM_DIV_H;
priv->type_pwm_clock_division_l[TYPEM] = M_PWM_DIV_L;
priv->type_pwm_clock_unit[TYPEM] = M_PWM_PERIOD;
aspeed_set_pwm_clock_values(priv->regmap, TYPEM, M_PWM_DIV_H,
M_PWM_DIV_L, M_PWM_PERIOD);
aspeed_set_tacho_type_enable(priv->regmap, TYPEM, true);
priv->type_fan_tach_clock_division[TYPEM] = M_TACH_CLK_DIV;
priv->type_fan_tach_unit[TYPEM] = M_TACH_UNIT;
aspeed_set_tacho_type_values(priv->regmap, TYPEM, M_TACH_MODE,
M_TACH_UNIT, M_TACH_CLK_DIV);
}
static void aspeed_create_pwm_port(struct aspeed_pwm_tacho_data *priv,
u8 pwm_port)
{
aspeed_set_pwm_port_enable(priv->regmap, pwm_port, true);
priv->pwm_present[pwm_port] = true;
priv->pwm_port_type[pwm_port] = TYPEM;
aspeed_set_pwm_port_type(priv->regmap, pwm_port, TYPEM);
priv->pwm_port_fan_ctrl[pwm_port] = INIT_FAN_CTRL;
aspeed_set_pwm_port_fan_ctrl(priv, pwm_port, INIT_FAN_CTRL);
}
static void aspeed_create_fan_tach_channel(struct aspeed_pwm_tacho_data *priv,
u8 *fan_tach_ch,
int count,
u8 pwm_source)
{
u8 val, index;
for (val = 0; val < count; val++) {
index = fan_tach_ch[val];
aspeed_set_fan_tach_ch_enable(priv->regmap, index, true);
priv->fan_tach_present[index] = true;
priv->fan_tach_ch_source[index] = pwm_source;
aspeed_set_fan_tach_ch_source(priv->regmap, index, pwm_source);
}
}
static int aspeed_create_fan(struct device *dev,
struct device_node *child,
struct aspeed_pwm_tacho_data *priv)
{
u8 *fan_tach_ch;
u32 pwm_port;
int ret, count;
ret = of_property_read_u32(child, "reg", &pwm_port);
if (ret)
return ret;
aspeed_create_pwm_port(priv, (u8)pwm_port);
count = of_property_count_u8_elems(child, "aspeed,fan-tach-ch");
if (count < 1)
return -EINVAL;
fan_tach_ch = devm_kzalloc(dev, sizeof(*fan_tach_ch) * count,
GFP_KERNEL);
if (!fan_tach_ch)
return -ENOMEM;
ret = of_property_read_u8_array(child, "aspeed,fan-tach-ch",
fan_tach_ch, count);
if (ret)
return ret;
aspeed_create_fan_tach_channel(priv, fan_tach_ch, count, pwm_port);
return 0;
}
static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np, *child;
struct aspeed_pwm_tacho_data *priv;
void __iomem *regs;
struct resource *res;
struct device *hwmon;
struct clk *clk;
int ret;
np = dev->of_node;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->regmap = devm_regmap_init(dev, NULL, (__force void *)regs,
&aspeed_pwm_tacho_regmap_config);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE, 0);
regmap_write(priv->regmap, ASPEED_PTCR_TACH_SOURCE_EXT, 0);
clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk))
return -ENODEV;
priv->clk_freq = clk_get_rate(clk);
aspeed_set_clock_enable(priv->regmap, true);
aspeed_set_clock_source(priv->regmap, 0);
aspeed_create_type(priv);
for_each_child_of_node(np, child) {
ret = aspeed_create_fan(dev, child, priv);
of_node_put(child);
if (ret)
return ret;
}
of_node_put(np);
priv->groups[0] = &pwm_dev_group;
priv->groups[1] = &fan_dev_group;
priv->groups[2] = NULL;
hwmon = devm_hwmon_device_register_with_groups(dev,
"aspeed_pwm_tacho",
priv, priv->groups);
return PTR_ERR_OR_ZERO(hwmon);
}
static const struct of_device_id of_pwm_tacho_match_table[] = {
{ .compatible = "aspeed,ast2400-pwm-tacho", },
{ .compatible = "aspeed,ast2500-pwm-tacho", },
{},
};
MODULE_DEVICE_TABLE(of, of_pwm_tacho_match_table);
static struct platform_driver aspeed_pwm_tacho_driver = {
.probe = aspeed_pwm_tacho_probe,
.driver = {
.name = "aspeed_pwm_tacho",
.of_match_table = of_pwm_tacho_match_table,
},
};
module_platform_driver(aspeed_pwm_tacho_driver);
MODULE_AUTHOR("Jaghathiswari Rankappagounder Natarajan <jaghu@google.com>");
MODULE_DESCRIPTION("ASPEED PWM and Fan Tacho device driver");
MODULE_LICENSE("GPL");
......@@ -995,6 +995,13 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
},
.driver_data = (void *)&i8k_config_data[DELL_XPS],
},
{
.ident = "Dell XPS 15 9560",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "XPS 15 9560"),
},
},
{ }
};
......
......@@ -186,7 +186,7 @@ static ssize_t hwmon_attr_show_string(struct device *dev,
char *buf)
{
struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr);
char *s;
const char *s;
int ret;
ret = hattr->ops->read_string(dev, hattr->type, hattr->attr,
......
......@@ -117,7 +117,7 @@ static long ina209_from_reg(const u8 reg, const u16 val)
case INA209_SHUNT_VOLTAGE_POS_WARN:
case INA209_SHUNT_VOLTAGE_NEG_WARN:
/* LSB=10 uV. Convert to mV. */
return DIV_ROUND_CLOSEST(val, 100);
return DIV_ROUND_CLOSEST((s16)val, 100);
case INA209_BUS_VOLTAGE:
case INA209_BUS_VOLTAGE_MAX_PEAK:
......@@ -146,7 +146,7 @@ static long ina209_from_reg(const u8 reg, const u16 val)
case INA209_CURRENT:
/* LSB=1 mA (selected). Is in mA */
return val;
return (s16)val;
}
/* programmer goofed */
......@@ -608,11 +608,18 @@ static const struct i2c_device_id ina209_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ina209_id);
static const struct of_device_id ina209_of_match[] = {
{ .compatible = "ti,ina209" },
{ },
};
MODULE_DEVICE_TABLE(of, ina209_of_match);
/* This is the driver that will be inserted */
static struct i2c_driver ina209_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "ina209",
.of_match_table = of_match_ptr(ina209_of_match),
},
.probe = ina209_probe,
.remove = ina209_remove,
......
......@@ -34,6 +34,7 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/util_macros.h>
......@@ -424,13 +425,19 @@ static int ina2xx_probe(struct i2c_client *client,
struct device *hwmon_dev;
u32 val;
int ret, group = 0;
enum ina2xx_ids chip;
if (client->dev.of_node)
chip = (enum ina2xx_ids)of_device_get_match_data(&client->dev);
else
chip = id->driver_data;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
/* set the device type */
data->config = &ina2xx_config[id->driver_data];
data->config = &ina2xx_config[chip];
if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) {
struct ina2xx_platform_data *pdata = dev_get_platdata(dev);
......@@ -487,9 +494,35 @@ static const struct i2c_device_id ina2xx_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ina2xx_id);
static const struct of_device_id ina2xx_of_match[] = {
{
.compatible = "ti,ina219",
.data = (void *)ina219
},
{
.compatible = "ti,ina220",
.data = (void *)ina219
},
{
.compatible = "ti,ina226",
.data = (void *)ina226
},
{
.compatible = "ti,ina230",
.data = (void *)ina226
},
{
.compatible = "ti,ina231",
.data = (void *)ina226
},
{ },
};
MODULE_DEVICE_TABLE(of, ina2xx_of_match);
static struct i2c_driver ina2xx_driver = {
.driver = {
.name = "ina2xx",
.of_match_table = of_match_ptr(ina2xx_of_match),
},
.probe = ina2xx_probe,
.id_table = ina2xx_id,
......
......@@ -46,6 +46,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/sysfs.h>
#include <linux/types.h>
......@@ -1115,6 +1116,10 @@ static int lm63_probe(struct i2c_client *client,
mutex_init(&data->update_lock);
/* Set the device type */
if (client->dev.of_node)
data->kind = (enum chips)of_device_get_match_data(&client->dev);
else
data->kind = id->driver_data;
data->kind = id->driver_data;
if (data->kind == lm64)
data->temp2_offset = 16000;
......@@ -1149,10 +1154,28 @@ static const struct i2c_device_id lm63_id[] = {
};
MODULE_DEVICE_TABLE(i2c, lm63_id);
static const struct of_device_id lm63_of_match[] = {
{
.compatible = "national,lm63",
.data = (void *)lm63
},
{
.compatible = "national,lm64",
.data = (void *)lm64
},
{
.compatible = "national,lm96163",
.data = (void *)lm96163
},
{ },
};
MODULE_DEVICE_TABLE(of, lm63_of_match);
static struct i2c_driver lm63_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm63",
.of_match_table = of_match_ptr(lm63_of_match),
},
.probe = lm63_probe,
.id_table = lm63_id,
......
......@@ -26,6 +26,7 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include "lm75.h"
......@@ -273,7 +274,12 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
int status, err;
u8 set_mask, clr_mask;
int new;
enum lm75_type kind = id->driver_data;
enum lm75_type kind;
if (client->dev.of_node)
kind = (enum lm75_type)of_device_get_match_data(&client->dev);
else
kind = id->driver_data;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
......@@ -424,6 +430,95 @@ static const struct i2c_device_id lm75_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, lm75_ids);
static const struct of_device_id lm75_of_match[] = {
{
.compatible = "adi,adt75",
.data = (void *)adt75
},
{
.compatible = "dallas,ds1775",
.data = (void *)ds1775
},
{
.compatible = "dallas,ds75",
.data = (void *)ds75
},
{
.compatible = "dallas,ds7505",
.data = (void *)ds7505
},
{
.compatible = "gmt,g751",
.data = (void *)g751
},
{
.compatible = "national,lm75",
.data = (void *)lm75
},
{
.compatible = "national,lm75a",
.data = (void *)lm75a
},
{
.compatible = "national,lm75b",
.data = (void *)lm75b
},
{
.compatible = "maxim,max6625",
.data = (void *)max6625
},
{
.compatible = "maxim,max6626",
.data = (void *)max6626
},
{
.compatible = "maxim,mcp980x",
.data = (void *)mcp980x
},
{
.compatible = "st,stds75",
.data = (void *)stds75
},
{
.compatible = "microchip,tcn75",
.data = (void *)tcn75
},
{
.compatible = "ti,tmp100",
.data = (void *)tmp100
},
{
.compatible = "ti,tmp101",
.data = (void *)tmp101
},
{
.compatible = "ti,tmp105",
.data = (void *)tmp105
},
{
.compatible = "ti,tmp112",
.data = (void *)tmp112
},
{
.compatible = "ti,tmp175",
.data = (void *)tmp175
},
{
.compatible = "ti,tmp275",
.data = (void *)tmp275
},
{
.compatible = "ti,tmp75",
.data = (void *)tmp75
},
{
.compatible = "ti,tmp75c",
.data = (void *)tmp75c
},
{ },
};
MODULE_DEVICE_TABLE(of, lm75_of_match);
#define LM75A_ID 0xA1
/* Return 0 if detection is successful, -ENODEV otherwise */
......@@ -560,6 +655,7 @@ static struct i2c_driver lm75_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm75",
.of_match_table = of_match_ptr(lm75_of_match),
.pm = LM75_DEV_PM_OPS,
},
.probe = lm75_probe,
......
......@@ -25,6 +25,7 @@
*/
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
......@@ -1552,7 +1553,10 @@ static int lm85_probe(struct i2c_client *client, const struct i2c_device_id *id)
return -ENOMEM;
data->client = client;
data->type = id->driver_data;
if (client->dev.of_node)
data->type = (enum chips)of_device_get_match_data(&client->dev);
else
data->type = id->driver_data;
mutex_init(&data->update_lock);
/* Fill in the chip specific driver values */
......@@ -1623,10 +1627,60 @@ static const struct i2c_device_id lm85_id[] = {
};
MODULE_DEVICE_TABLE(i2c, lm85_id);
static const struct of_device_id lm85_of_match[] = {
{
.compatible = "adi,adm1027",
.data = (void *)adm1027
},
{
.compatible = "adi,adt7463",
.data = (void *)adt7463
},
{
.compatible = "adi,adt7468",
.data = (void *)adt7468
},
{
.compatible = "national,lm85",
.data = (void *)lm85
},
{
.compatible = "national,lm85b",
.data = (void *)lm85
},
{
.compatible = "national,lm85c",
.data = (void *)lm85
},
{
.compatible = "smsc,emc6d100",
.data = (void *)emc6d100
},
{
.compatible = "smsc,emc6d101",
.data = (void *)emc6d100
},
{
.compatible = "smsc,emc6d102",
.data = (void *)emc6d102
},
{
.compatible = "smsc,emc6d103",
.data = (void *)emc6d103
},
{
.compatible = "smsc,emc6d103s",
.data = (void *)emc6d103s
},
{ },
};
MODULE_DEVICE_TABLE(of, lm85_of_match);
static struct i2c_driver lm85_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm85",
.of_match_table = of_match_ptr(lm85_of_match),
},
.probe = lm85_probe,
.id_table = lm85_id,
......
......@@ -66,6 +66,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/regulator/consumer.h>
/*
* Addresses to scan
......@@ -74,8 +75,6 @@
static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
enum chips { lm87, adm1024 };
/*
* The LM87 registers
*/
......@@ -855,8 +854,26 @@ static int lm87_init_client(struct i2c_client *client)
{
struct lm87_data *data = i2c_get_clientdata(client);
int rc;
if (dev_get_platdata(&client->dev)) {
struct device_node *of_node = client->dev.of_node;
u8 val = 0;
struct regulator *vcc = NULL;
if (of_node) {
if (of_property_read_bool(of_node, "has-temp3"))
val |= CHAN_TEMP3;
if (of_property_read_bool(of_node, "has-in6"))
val |= CHAN_NO_FAN(0);
if (of_property_read_bool(of_node, "has-in7"))
val |= CHAN_NO_FAN(1);
vcc = devm_regulator_get_optional(&client->dev, "vcc");
if (!IS_ERR(vcc)) {
if (regulator_get_voltage(vcc) == 5000000)
val |= CHAN_VCC_5V;
}
data->channel = val;
lm87_write_value(client,
LM87_REG_CHANNEL_MODE, data->channel);
} else if (dev_get_platdata(&client->dev)) {
data->channel = *(u8 *)dev_get_platdata(&client->dev);
lm87_write_value(client,
LM87_REG_CHANNEL_MODE, data->channel);
......@@ -962,16 +979,24 @@ static int lm87_probe(struct i2c_client *client, const struct i2c_device_id *id)
*/
static const struct i2c_device_id lm87_id[] = {
{ "lm87", lm87 },
{ "adm1024", adm1024 },
{ "lm87", 0 },
{ "adm1024", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm87_id);
static const struct of_device_id lm87_of_match[] = {
{ .compatible = "ti,lm87" },
{ .compatible = "adi,adm1024" },
{ },
};
MODULE_DEVICE_TABLE(of, lm87_of_match);
static struct i2c_driver lm87_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm87",
.of_match_table = lm87_of_match,
},
.probe = lm87_probe,
.id_table = lm87_id,
......
......@@ -92,6 +92,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/sysfs.h>
#include <linux/interrupt.h>
#include <linux/regulator/consumer.h>
......@@ -235,6 +236,99 @@ static const struct i2c_device_id lm90_id[] = {
};
MODULE_DEVICE_TABLE(i2c, lm90_id);
static const struct of_device_id lm90_of_match[] = {
{
.compatible = "adi,adm1032",
.data = (void *)adm1032
},
{
.compatible = "adi,adt7461",
.data = (void *)adt7461
},
{
.compatible = "adi,adt7461a",
.data = (void *)adt7461
},
{
.compatible = "gmt,g781",
.data = (void *)g781
},
{
.compatible = "national,lm90",
.data = (void *)lm90
},
{
.compatible = "national,lm86",
.data = (void *)lm86
},
{
.compatible = "national,lm89",
.data = (void *)lm86
},
{
.compatible = "national,lm99",
.data = (void *)lm99
},
{
.compatible = "dallas,max6646",
.data = (void *)max6646
},
{
.compatible = "dallas,max6647",
.data = (void *)max6646
},
{
.compatible = "dallas,max6649",
.data = (void *)max6646
},
{
.compatible = "dallas,max6657",
.data = (void *)max6657
},
{
.compatible = "dallas,max6658",
.data = (void *)max6657
},
{
.compatible = "dallas,max6659",
.data = (void *)max6659
},
{
.compatible = "dallas,max6680",
.data = (void *)max6680
},
{
.compatible = "dallas,max6681",
.data = (void *)max6680
},
{
.compatible = "dallas,max6695",
.data = (void *)max6696
},
{
.compatible = "dallas,max6696",
.data = (void *)max6696
},
{
.compatible = "onnn,nct1008",
.data = (void *)adt7461
},
{
.compatible = "winbond,w83l771",
.data = (void *)w83l771
},
{
.compatible = "nxp,sa56004",
.data = (void *)sa56004
},
{
.compatible = "ti,tmp451",
.data = (void *)tmp451
},
{ },
};
MODULE_DEVICE_TABLE(of, lm90_of_match);
/*
* chip type specific parameters
*/
......@@ -1677,7 +1771,10 @@ static int lm90_probe(struct i2c_client *client,
mutex_init(&data->update_lock);
/* Set the device type */
data->kind = id->driver_data;
if (client->dev.of_node)
data->kind = (enum chips)of_device_get_match_data(&client->dev);
else
data->kind = id->driver_data;
if (data->kind == adm1032) {
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
client->flags &= ~I2C_CLIENT_PEC;
......@@ -1816,6 +1913,7 @@ static struct i2c_driver lm90_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm90",
.of_match_table = of_match_ptr(lm90_of_match),
},
.probe = lm90_probe,
.alert = lm90_alert,
......
......@@ -622,10 +622,18 @@ static const struct i2c_device_id lm95245_id[] = {
};
MODULE_DEVICE_TABLE(i2c, lm95245_id);
static const struct of_device_id lm95245_of_match[] = {
{ .compatible = "national,lm95235" },
{ .compatible = "national,lm95245" },
{ },
};
MODULE_DEVICE_TABLE(of, lm95245_of_match);
static struct i2c_driver lm95245_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm95245",
.of_match_table = of_match_ptr(lm95245_of_match),
},
.probe = lm95245_probe,
.id_table = lm95245_id,
......
......@@ -24,6 +24,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_data/max6697.h>
......@@ -632,7 +633,10 @@ static int max6697_probe(struct i2c_client *client,
if (!data)
return -ENOMEM;
data->type = id->driver_data;
if (client->dev.of_node)
data->type = (enum chips)of_device_get_match_data(&client->dev);
else
data->type = id->driver_data;
data->chip = &max6697_chip_data[data->type];
data->client = client;
mutex_init(&data->update_lock);
......@@ -662,10 +666,56 @@ static const struct i2c_device_id max6697_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max6697_id);
static const struct of_device_id max6697_of_match[] = {
{
.compatible = "maxim,max6581",
.data = (void *)max6581
},
{
.compatible = "maxim,max6602",
.data = (void *)max6602
},
{
.compatible = "maxim,max6622",
.data = (void *)max6622
},
{
.compatible = "maxim,max6636",
.data = (void *)max6636
},
{
.compatible = "maxim,max6689",
.data = (void *)max6689
},
{
.compatible = "maxim,max6693",
.data = (void *)max6693
},
{
.compatible = "maxim,max6694",
.data = (void *)max6694
},
{
.compatible = "maxim,max6697",
.data = (void *)max6697
},
{
.compatible = "maxim,max6698",
.data = (void *)max6698
},
{
.compatible = "maxim,max6699",
.data = (void *)max6699
},
{ },
};
MODULE_DEVICE_TABLE(of, max6697_of_match);
static struct i2c_driver max6697_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "max6697",
.of_match_table = of_match_ptr(max6697_of_match),
},
.probe = max6697_probe,
.id_table = max6697_id,
......
......@@ -101,8 +101,8 @@ static const struct coefficients adm1075_coefficients[] = {
[0] = { 27169, 0, -1 }, /* voltage */
[1] = { 806, 20475, -1 }, /* current, irange25 */
[2] = { 404, 20475, -1 }, /* current, irange50 */
[3] = { 0, -1, 8549 }, /* power, irange25 */
[4] = { 0, -1, 4279 }, /* power, irange50 */
[3] = { 8549, 0, -1 }, /* power, irange25 */
[4] = { 4279, 0, -1 }, /* power, irange50 */
};
static const struct coefficients adm1275_coefficients[] = {
......
......@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
......@@ -119,6 +120,35 @@ static const struct i2c_device_id ucd9000_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ucd9000_id);
static const struct of_device_id ucd9000_of_match[] = {
{
.compatible = "ti,ucd9000",
.data = (void *)ucd9000
},
{
.compatible = "ti,ucd90120",
.data = (void *)ucd90120
},
{
.compatible = "ti,ucd90124",
.data = (void *)ucd90124
},
{
.compatible = "ti,ucd90160",
.data = (void *)ucd90160
},
{
.compatible = "ti,ucd9090",
.data = (void *)ucd9090
},
{
.compatible = "ti,ucd90910",
.data = (void *)ucd90910
},
{ },
};
MODULE_DEVICE_TABLE(of, ucd9000_of_match);
static int ucd9000_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
......@@ -126,6 +156,7 @@ static int ucd9000_probe(struct i2c_client *client,
struct ucd9000_data *data;
struct pmbus_driver_info *info;
const struct i2c_device_id *mid;
enum chips chip;
int i, ret;
if (!i2c_check_functionality(client->adapter,
......@@ -151,7 +182,12 @@ static int ucd9000_probe(struct i2c_client *client,
return -ENODEV;
}
if (id->driver_data != ucd9000 && id->driver_data != mid->driver_data)
if (client->dev.of_node)
chip = (enum chips)of_device_get_match_data(&client->dev);
else
chip = id->driver_data;
if (chip != ucd9000 && chip != mid->driver_data)
dev_notice(&client->dev,
"Device mismatch: Configured %s, detected %s\n",
id->name, mid->name);
......@@ -234,6 +270,7 @@ static int ucd9000_probe(struct i2c_client *client,
static struct i2c_driver ucd9000_driver = {
.driver = {
.name = "ucd9000",
.of_match_table = of_match_ptr(ucd9000_of_match),
},
.probe = ucd9000_probe,
.remove = pmbus_do_remove,
......
......@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
......@@ -46,12 +47,50 @@ static const struct i2c_device_id ucd9200_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ucd9200_id);
static const struct of_device_id ucd9200_of_match[] = {
{
.compatible = "ti,cd9200",
.data = (void *)ucd9200
},
{
.compatible = "ti,cd9220",
.data = (void *)ucd9220
},
{
.compatible = "ti,cd9222",
.data = (void *)ucd9222
},
{
.compatible = "ti,cd9224",
.data = (void *)ucd9224
},
{
.compatible = "ti,cd9240",
.data = (void *)ucd9240
},
{
.compatible = "ti,cd9244",
.data = (void *)ucd9244
},
{
.compatible = "ti,cd9246",
.data = (void *)ucd9246
},
{
.compatible = "ti,cd9248",
.data = (void *)ucd9248
},
{ },
};
MODULE_DEVICE_TABLE(of, ucd9200_of_match);
static int ucd9200_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
struct pmbus_driver_info *info;
const struct i2c_device_id *mid;
enum chips chip;
int i, j, ret;
if (!i2c_check_functionality(client->adapter,
......@@ -76,7 +115,13 @@ static int ucd9200_probe(struct i2c_client *client,
dev_err(&client->dev, "Unsupported device\n");
return -ENODEV;
}
if (id->driver_data != ucd9200 && id->driver_data != mid->driver_data)
if (client->dev.of_node)
chip = (enum chips)of_device_get_match_data(&client->dev);
else
chip = id->driver_data;
if (chip != ucd9200 && chip != mid->driver_data)
dev_notice(&client->dev,
"Device mismatch: Configured %s, detected %s\n",
id->name, mid->name);
......@@ -167,6 +212,7 @@ static int ucd9200_probe(struct i2c_client *client,
static struct i2c_driver ucd9200_driver = {
.driver = {
.name = "ucd9200",
.of_match_table = of_match_ptr(ucd9200_of_match),
},
.probe = ucd9200_probe,
.remove = pmbus_do_remove,
......
......@@ -85,6 +85,12 @@ static const struct i2c_device_id stts751_id[] = {
{ }
};
static const struct of_device_id stts751_of_match[] = {
{ .compatible = "stts751" },
{ },
};
MODULE_DEVICE_TABLE(of, stts751_of_match);
struct stts751_priv {
struct device *dev;
struct i2c_client *client;
......@@ -819,6 +825,7 @@ static struct i2c_driver stts751_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = DEVNAME,
.of_match_table = of_match_ptr(stts751_of_match),
},
.probe = stts751_probe,
.id_table = stts751_id,
......
......@@ -323,8 +323,15 @@ static const struct i2c_device_id tmp102_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tmp102_id);
static const struct of_device_id tmp102_of_match[] = {
{ .compatible = "ti,tmp102" },
{ },
};
MODULE_DEVICE_TABLE(of, tmp102_of_match);
static struct i2c_driver tmp102_driver = {
.driver.name = DRIVER_NAME,
.driver.of_match_table = of_match_ptr(tmp102_of_match),
.driver.pm = &tmp102_dev_pm_ops,
.probe = tmp102_probe,
.id_table = tmp102_id,
......
......@@ -150,8 +150,7 @@ static int tmp103_probe(struct i2c_client *client,
return PTR_ERR_OR_ZERO(hwmon_dev);
}
#ifdef CONFIG_PM
static int tmp103_suspend(struct device *dev)
static int __maybe_unused tmp103_suspend(struct device *dev)
{
struct regmap *regmap = dev_get_drvdata(dev);
......@@ -159,7 +158,7 @@ static int tmp103_suspend(struct device *dev)
TMP103_CONF_SD_MASK, 0);
}
static int tmp103_resume(struct device *dev)
static int __maybe_unused tmp103_resume(struct device *dev)
{
struct regmap *regmap = dev_get_drvdata(dev);
......@@ -167,15 +166,7 @@ static int tmp103_resume(struct device *dev)
TMP103_CONF_SD_MASK, TMP103_CONF_SD);
}
static const struct dev_pm_ops tmp103_dev_pm_ops = {
.suspend = tmp103_suspend,
.resume = tmp103_resume,
};
#define TMP103_DEV_PM_OPS (&tmp103_dev_pm_ops)
#else
#define TMP103_DEV_PM_OPS NULL
#endif /* CONFIG_PM */
static SIMPLE_DEV_PM_OPS(tmp103_dev_pm_ops, tmp103_suspend, tmp103_resume);
static const struct i2c_device_id tmp103_id[] = {
{ "tmp103", 0 },
......@@ -183,10 +174,17 @@ static const struct i2c_device_id tmp103_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tmp103_id);
static const struct of_device_id tmp103_of_match[] = {
{ .compatible = "ti,tmp103" },
{ },
};
MODULE_DEVICE_TABLE(of, tmp103_of_match);
static struct i2c_driver tmp103_driver = {
.driver = {
.name = "tmp103",
.pm = TMP103_DEV_PM_OPS,
.of_match_table = of_match_ptr(tmp103_of_match),
.pm = &tmp103_dev_pm_ops,
},
.probe = tmp103_probe,
.id_table = tmp103_id,
......
......@@ -29,6 +29,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/sysfs.h>
/* Addresses to scan */
......@@ -69,6 +70,31 @@ static const struct i2c_device_id tmp421_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tmp421_id);
static const struct of_device_id tmp421_of_match[] = {
{
.compatible = "ti,tmp421",
.data = (void *)2
},
{
.compatible = "ti,tmp422",
.data = (void *)3
},
{
.compatible = "ti,tmp423",
.data = (void *)4
},
{
.compatible = "ti,tmp441",
.data = (void *)2
},
{
.compatible = "ti,tmp422",
.data = (void *)3
},
{ },
};
MODULE_DEVICE_TABLE(of, tmp421_of_match);
struct tmp421_data {
struct i2c_client *client;
struct mutex update_lock;
......@@ -78,7 +104,7 @@ struct tmp421_data {
struct hwmon_chip_info chip;
char valid;
unsigned long last_updated;
int channels;
unsigned long channels;
u8 config;
s16 temp[4];
};
......@@ -272,7 +298,11 @@ static int tmp421_probe(struct i2c_client *client,
return -ENOMEM;
mutex_init(&data->update_lock);
data->channels = id->driver_data;
if (client->dev.of_node)
data->channels = (unsigned long)
of_device_get_match_data(&client->dev);
else
data->channels = id->driver_data;
data->client = client;
err = tmp421_init_client(client);
......@@ -301,6 +331,7 @@ static struct i2c_driver tmp421_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "tmp421",
.of_match_table = of_match_ptr(tmp421_of_match),
},
.probe = tmp421_probe,
.id_table = tmp421_id,
......
/*
*
* TWL4030 MADC Hwmon driver-This driver monitors the real time
* conversion of analog signals like battery temperature,
* battery type, battery level etc. User can ask for the conversion on a
* particular channel using the sysfs nodes.
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* J Keerthy <j-keerthy@ti.com>
*
* 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.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c/twl.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/i2c/twl4030-madc.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/stddef.h>
#include <linux/sysfs.h>
#include <linux/err.h>
#include <linux/types.h>
/*
* sysfs hook function
*/
static ssize_t madc_read(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct twl4030_madc_request req = {
.channels = 1 << attr->index,
.method = TWL4030_MADC_SW2,
.type = TWL4030_MADC_WAIT,
};
long val;
val = twl4030_madc_conversion(&req);
if (val < 0)
return val;
return sprintf(buf, "%d\n", req.rbuf[attr->index]);
}
/* sysfs nodes to read individual channels from user side */
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, madc_read, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, madc_read, NULL, 1);
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, madc_read, NULL, 2);
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, madc_read, NULL, 3);
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, madc_read, NULL, 4);
static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, madc_read, NULL, 5);
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, madc_read, NULL, 6);
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, madc_read, NULL, 7);
static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, madc_read, NULL, 8);
static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, madc_read, NULL, 9);
static SENSOR_DEVICE_ATTR(curr10_input, S_IRUGO, madc_read, NULL, 10);
static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, madc_read, NULL, 11);
static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, madc_read, NULL, 12);
static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, madc_read, NULL, 15);
static struct attribute *twl4030_madc_attrs[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in5_input.dev_attr.attr,
&sensor_dev_attr_in6_input.dev_attr.attr,
&sensor_dev_attr_in7_input.dev_attr.attr,
&sensor_dev_attr_in8_input.dev_attr.attr,
&sensor_dev_attr_in9_input.dev_attr.attr,
&sensor_dev_attr_curr10_input.dev_attr.attr,
&sensor_dev_attr_in11_input.dev_attr.attr,
&sensor_dev_attr_in12_input.dev_attr.attr,
&sensor_dev_attr_in15_input.dev_attr.attr,
NULL
};
ATTRIBUTE_GROUPS(twl4030_madc);
static int twl4030_madc_hwmon_probe(struct platform_device *pdev)
{
struct device *hwmon;
hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
"twl4030_madc", NULL,
twl4030_madc_groups);
return PTR_ERR_OR_ZERO(hwmon);
}
static struct platform_driver twl4030_madc_hwmon_driver = {
.probe = twl4030_madc_hwmon_probe,
.driver = {
.name = "twl4030_madc_hwmon",
},
};
module_platform_driver(twl4030_madc_hwmon_driver);
MODULE_DESCRIPTION("TWL4030 ADC Hwmon driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("J Keerthy");
MODULE_ALIAS("platform:twl4030_madc_hwmon");
......@@ -135,11 +135,16 @@ superio_select(int ioreg, int ld)
outb(ld, ioreg + 1);
}
static inline void
static inline int
superio_enter(int ioreg)
{
if (!request_muxed_region(ioreg, 2, DRVNAME))
return -EBUSY;
outb(0x87, ioreg);
outb(0x87, ioreg);
return 0;
}
static inline void
......@@ -148,6 +153,7 @@ superio_exit(int ioreg)
outb(0xaa, ioreg);
outb(0x02, ioreg);
outb(0x02, ioreg + 1);
release_region(ioreg, 2);
}
/*
......@@ -1970,8 +1976,6 @@ w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data,
return;
}
superio_enter(sio_data->sioreg);
/* fan4 and fan5 share some pins with the GPIO and serial flash */
if (sio_data->kind == nct6775) {
/* On NCT6775, fan4 shares pins with the fdc interface */
......@@ -2013,8 +2017,6 @@ w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data,
fan4min = fan4pin;
}
superio_exit(sio_data->sioreg);
data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
data->has_fan |= (fan3pin << 2);
data->has_fan_min |= (fan3pin << 2);
......@@ -2352,7 +2354,11 @@ static int w83627ehf_probe(struct platform_device *pdev)
w83627ehf_init_device(data, sio_data->kind);
data->vrm = vid_which_vrm();
superio_enter(sio_data->sioreg);
err = superio_enter(sio_data->sioreg);
if (err)
goto exit_release;
/* Read VID value */
if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b ||
sio_data->kind == nct6775 || sio_data->kind == nct6776) {
......@@ -2364,8 +2370,10 @@ static int w83627ehf_probe(struct platform_device *pdev)
superio_select(sio_data->sioreg, W83667HG_LD_VID);
data->vid = superio_inb(sio_data->sioreg, 0xe3);
err = device_create_file(dev, &dev_attr_cpu0_vid);
if (err)
if (err) {
superio_exit(sio_data->sioreg);
goto exit_release;
}
} else if (sio_data->kind != w83627uhg) {
superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
......@@ -2401,8 +2409,10 @@ static int w83627ehf_probe(struct platform_device *pdev)
data->vid &= 0x3f;
err = device_create_file(dev, &dev_attr_cpu0_vid);
if (err)
if (err) {
superio_exit(sio_data->sioreg);
goto exit_release;
}
} else {
dev_info(dev,
"VID pins in output mode, CPU VID not available\n");
......@@ -2424,10 +2434,10 @@ static int w83627ehf_probe(struct platform_device *pdev)
pr_info("Enabled fan debounce for chip %s\n", data->name);
}
superio_exit(sio_data->sioreg);
w83627ehf_check_fan_inputs(sio_data, data);
superio_exit(sio_data->sioreg);
/* Read fan clock dividers immediately */
w83627ehf_update_fan_div_common(dev, data);
......@@ -2712,8 +2722,11 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
u16 val;
const char *sio_name;
int err;
superio_enter(sioaddr);
err = superio_enter(sioaddr);
if (err)
return err;
if (force_id)
val = force_id;
......
......@@ -337,7 +337,7 @@ struct hwmon_ops {
int (*read)(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val);
int (*read_string)(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, char **str);
u32 attr, int channel, const char **str);
int (*write)(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment