blob: b54b573eeda5770af0bab91f9b45720abcf9db9c [file] [log] [blame]
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt
index 6ec3c8d79f49..80acd6849648 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt
@@ -144,3 +144,38 @@ gpio21: gpio@21 {
bias-pull-up;
};
};
+
+Line naming
+===========
+
+Because several gpio_chip instances are hidden below a single device tree
+node, it is necessary to split the names into several child nodes. Ensure
+that the configured addresses match those in the microchip,spi-present-mask:
+
+gpio@0 {
+ compatible = "microchip,mcp23s17";
+ gpio-controller;
+ #gpio-cells = <2>;
+ /* this bitmask has bits #0 (0x01) and #2 (0x04) set */
+ spi-present-mask = <0x05>;
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+
+ gpio-bank@1 {
+ address = <0>;
+ gpio-line-names =
+ "GPA0",
+ "GPA1",
+ ...
+ "GPA7",
+ "GPB0",
+ "GPB1",
+ ...
+ "GPB7";
+ };
+
+ gpio-bank@2 {
+ address = <2>;
+ gpio-line-names = ...
+ };
+};
diff --git a/Documentation/hwmon/fsp-3y.rst b/Documentation/hwmon/fsp-3y.rst
new file mode 100644
index 000000000000..5693d83a2035
--- /dev/null
+++ b/Documentation/hwmon/fsp-3y.rst
@@ -0,0 +1,28 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver fsp3y
+======================
+Supported devices:
+ * 3Y POWER YH-5151E
+ * 3Y POWER YM-2151E
+
+Author: Václav Kubernát <kubernat@cesnet.cz>
+
+Description
+-----------
+This driver implements limited support for two 3Y POWER devices.
+
+Sysfs entries
+-------------
+ * in1_input input voltage
+ * in2_input 12V output voltage
+ * in3_input 5V output voltage
+ * curr1_input input current
+ * curr2_input 12V output current
+ * curr3_input 5V output current
+ * fan1_input fan rpm
+ * temp1_input temperature 1
+ * temp2_input temperature 2
+ * temp3_input temperature 3
+ * power1_input input power
+ * power2_input output power
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 8d5a2df1ecb6..ed32c0f200bb 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -62,6 +62,7 @@ Hardware Monitoring Kernel Drivers
f71805f
f71882fg
fam15h_power
+ fsp-3y
ftsteutates
g760a
g762
diff --git a/Documentation/hwmon/max31790.rst b/Documentation/hwmon/max31790.rst
index f301385d8cef..e70aae9f71a2 100644
--- a/Documentation/hwmon/max31790.rst
+++ b/Documentation/hwmon/max31790.rst
@@ -30,14 +30,58 @@ monitoring and control of fan RPM as well as detection of fan failure.
Six pins are dedicated tachometer inputs. Any of the six PWM outputs can
also be configured to serve as tachometer inputs.
+About pwm[1-6]_enable
+---------------------
+0 - full-speed
+ The chip doesn't have a specific way to set "full speed", so setting
+ pwm[1-6]_enable to 0 is just "set PWM mode with 255 duty cycle".
+1 - PWM mode
+ Fan speed is controlled by writing a value to pwm[1-6].
+2 - RPM mode
+ Fan speed is controlled by writing a value to fan[1-6]_target.
+
+About fan[1-6]_fault
+--------------------
+In PWM (or full-speed) mode, if the input RPM goes below what is set
+in fan[1-6]_target, fan[1-6]_fault gets set to 1. In other words,
+fan[1-6]_target works as the minimum input RPM before a fan fault goes off.
+
+In RPM mode, fan fault is set when the fan spins "too slowly" (exact
+conditions are in the datasheet). RPM mode depends on four variables:
+ target_speed: This is set by fan[1-6]_target.
+ speed_range: This is set automatically when setting target_speed
+ or manually by fan[1-12]_div.
+ pwm_rate_of_change: NOT set by the driver.
+ fan_window: NOT set by the driver.
+
+The last two values are not set by the driver, because there's no generic way to
+compute them. You should set them manually through i2c (in the bootloader for
+example). Check the datasheet for details.
+
+The fan fault value latches, to reset it, set a value to pwm[1-6]
+or fan[1-6]_target.
+
+About fan[1-12]_div
+-------------------
+This value affects the measurable range of the chip. The driver sets this value
+automatically in RPM based on fan[1-6]_target. In PWM mode, you should set this
+value manually based on the details from the datasheet. Setting the speed range
+is disabled while in RPM mode to prevent overwriting the automatically
+calculated value.
Sysfs entries
-------------
-================== === =======================================================
+================== === =============================================================
+fan[1-12]_enable RW enable fan speed monitoring
fan[1-12]_input RO fan tachometer speed in RPM
fan[1-12]_fault RO fan experienced fault
-fan[1-6]_target RW desired fan speed in RPM
-pwm[1-6]_enable RW regulator mode, 0=disabled, 1=manual mode, 2=rpm mode
+fan[1-12]_div RW set the measurable speed range, not available in RPM mode
+fan[1-6]_target RW RPM mode = desired fan speed
+ PWM mode = minimum fan speed until fault
+pwm[1-6]_enable RW regulator mode, 0=no control, sets 0% PWM,
+ 1=manual (pwm) mode,
+ 2=rpm mode
+ setting rpm mode sets fan*_enable to 1
pwm[1-6] RW fan target duty cycle (0-255)
-================== === =======================================================
+================== === =============================================================
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 54f04e61fb83..c2ec57672c4e 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1092,6 +1092,7 @@ config SENSORS_MAX6697
config SENSORS_MAX31790
tristate "Maxim MAX31790 sensor chip"
depends on I2C
+ select REGMAP_I2C
help
If you say yes here you get support for 6-Channel PWM-Output
Fan RPM Controller.
diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c
index 86e6c71db685..8b04f4c01752 100644
--- a/drivers/hwmon/max31790.c
+++ b/drivers/hwmon/max31790.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/module.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
/* MAX31790 registers */
@@ -29,6 +30,7 @@
#define MAX31790_FAN_CFG_RPM_MODE 0x80
#define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08
#define MAX31790_FAN_CFG_TACH_INPUT 0x01
+#define MAX31790_FAN_CFG_CTRL_MON 0x10
/* Fan Dynamics register bits */
#define MAX31790_FAN_DYN_SR_SHIFT 5
@@ -46,92 +48,53 @@
#define NR_CHANNEL 6
+#define MAX31790_REG_USER_BYTE_67 0x67
+
+#define BULK_TO_U16(msb, lsb) (((msb) << 8) + (lsb))
+#define U16_MSB(num) (((num) & 0xFF00) >> 8)
+#define U16_LSB(num) ((num) & 0x00FF)
+
+static const struct regmap_range max31790_ro_range = {
+ .range_min = MAX31790_REG_TACH_COUNT(0),
+ .range_max = MAX31790_REG_PWMOUT(0) - 1,
+};
+
+static const struct regmap_access_table max31790_wr_table = {
+ .no_ranges = &max31790_ro_range,
+ .n_no_ranges = 1,
+};
+
+static const struct regmap_range max31790_volatile_ranges[] = {
+ regmap_reg_range(MAX31790_REG_TACH_COUNT(0), MAX31790_REG_TACH_COUNT(12)),
+ regmap_reg_range(MAX31790_REG_FAN_FAULT_STATUS2, MAX31790_REG_FAN_FAULT_STATUS1),
+};
+
+static const struct regmap_access_table max31790_volatile_table = {
+ .no_ranges = max31790_volatile_ranges,
+ .n_no_ranges = 2,
+ .n_yes_ranges = 0
+};
+
+static const struct regmap_config max31790_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_stride = 1,
+ .max_register = MAX31790_REG_USER_BYTE_67,
+ .wr_table = &max31790_wr_table,
+ .volatile_table = &max31790_volatile_table
+};
+
/*
* Client data (each client gets its own)
*/
struct max31790_data {
- struct i2c_client *client;
+ struct regmap *regmap;
+
struct mutex update_lock;
- bool valid; /* zero until following fields are valid */
- unsigned long last_updated; /* in jiffies */
-
- /* register values */
u8 fan_config[NR_CHANNEL];
u8 fan_dynamics[NR_CHANNEL];
- u16 fault_status;
- u16 tach[NR_CHANNEL * 2];
- u16 pwm[NR_CHANNEL];
- u16 target_count[NR_CHANNEL];
};
-static struct max31790_data *max31790_update_device(struct device *dev)
-{
- struct max31790_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
- struct max31790_data *ret = data;
- int i;
- int rv;
-
- mutex_lock(&data->update_lock);
-
- if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- rv = i2c_smbus_read_byte_data(client,
- MAX31790_REG_FAN_FAULT_STATUS1);
- if (rv < 0)
- goto abort;
- data->fault_status = rv & 0x3F;
-
- rv = i2c_smbus_read_byte_data(client,
- MAX31790_REG_FAN_FAULT_STATUS2);
- if (rv < 0)
- goto abort;
- data->fault_status |= (rv & 0x3F) << 6;
-
- for (i = 0; i < NR_CHANNEL; i++) {
- rv = i2c_smbus_read_word_swapped(client,
- MAX31790_REG_TACH_COUNT(i));
- if (rv < 0)
- goto abort;
- data->tach[i] = rv;
-
- if (data->fan_config[i]
- & MAX31790_FAN_CFG_TACH_INPUT) {
- rv = i2c_smbus_read_word_swapped(client,
- MAX31790_REG_TACH_COUNT(NR_CHANNEL
- + i));
- if (rv < 0)
- goto abort;
- data->tach[NR_CHANNEL + i] = rv;
- } else {
- rv = i2c_smbus_read_word_swapped(client,
- MAX31790_REG_PWMOUT(i));
- if (rv < 0)
- goto abort;
- data->pwm[i] = rv;
-
- rv = i2c_smbus_read_word_swapped(client,
- MAX31790_REG_TARGET_COUNT(i));
- if (rv < 0)
- goto abort;
- data->target_count[i] = rv;
- }
- }
-
- data->last_updated = jiffies;
- data->valid = true;
- }
- goto done;
-
-abort:
- data->valid = false;
- ret = ERR_PTR(rv);
-
-done:
- mutex_unlock(&data->update_lock);
-
- return ret;
-}
-
static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 };
static u8 get_tach_period(u8 fan_dynamics)
@@ -159,28 +122,109 @@ static u8 bits_for_tach_period(int rpm)
return bits;
}
+static int read_reg_byte(struct regmap *regmap, u8 reg)
+{
+ int rv;
+ int val;
+
+ rv = regmap_read(regmap, reg, &val);
+ if (rv < 0)
+ return rv;
+
+ return val;
+}
+
+static int read_reg_word(struct regmap *regmap, u8 reg)
+{
+ int rv;
+ u8 val_bulk[2];
+
+ rv = regmap_bulk_read(regmap, reg, val_bulk, 2);
+ if (rv < 0)
+ return rv;
+
+ return BULK_TO_U16(val_bulk[0], val_bulk[1]);
+}
+
+static int write_reg_word(struct regmap *regmap, u8 reg, u16 val)
+{
+ u8 bulk_val[2];
+
+ bulk_val[0] = U16_MSB(val);
+ bulk_val[1] = U16_LSB(val);
+
+ return regmap_bulk_write(regmap, reg, bulk_val, 2);
+}
+
+static int bits_for_speed_range(long speed_range)
+{
+ switch (speed_range) {
+ case 1:
+ return 0x0;
+ case 2:
+ return 0x1;
+ case 4:
+ return 0x2;
+ case 8:
+ return 0x3;
+ case 16:
+ return 0x4;
+ case 32:
+ return 0x5;
+ default:
+ return -1;
+ }
+}
+
static int max31790_read_fan(struct device *dev, u32 attr, int channel,
long *val)
{
- struct max31790_data *data = max31790_update_device(dev);
- int sr, rpm;
-
- if (IS_ERR(data))
- return PTR_ERR(data);
+ struct max31790_data *data = dev_get_drvdata(dev);
+ struct regmap *regmap = data->regmap;
+ int tach, fault;
switch (attr) {
case hwmon_fan_input:
- sr = get_tach_period(data->fan_dynamics[channel]);
- rpm = RPM_FROM_REG(data->tach[channel], sr);
- *val = rpm;
+ if (!(data->fan_config[channel] & MAX31790_FAN_CFG_TACH_INPUT_EN))
+ return -ENODATA;
+
+ tach = read_reg_word(regmap, MAX31790_REG_TACH_COUNT(channel));
+ if (tach < 0)
+ return tach;
+
+ *val = RPM_FROM_REG(tach, get_tach_period(data->fan_dynamics[channel]));
return 0;
case hwmon_fan_target:
- sr = get_tach_period(data->fan_dynamics[channel]);
- rpm = RPM_FROM_REG(data->target_count[channel], sr);
- *val = rpm;
+ tach = read_reg_word(regmap, MAX31790_REG_TARGET_COUNT(channel));
+ if (tach < 0)
+ return tach;
+
+ *val = RPM_FROM_REG(tach, get_tach_period(data->fan_dynamics[channel]));
return 0;
case hwmon_fan_fault:
- *val = !!(data->fault_status & (1 << channel));
+ if (!(data->fan_config[channel] & MAX31790_FAN_CFG_TACH_INPUT_EN)) {
+ *val = 0;
+ return 0;
+ }
+
+ if (channel > 6)
+ fault = read_reg_byte(regmap, MAX31790_REG_FAN_FAULT_STATUS2);
+ else
+ fault = read_reg_byte(regmap, MAX31790_REG_FAN_FAULT_STATUS1);
+
+ if (fault < 0)
+ return fault;
+
+ if (channel > 6)
+ *val = !!(fault & (1 << (channel - 6)));
+ else
+ *val = !!(fault & (1 << channel));
+ return 0;
+ case hwmon_fan_enable:
+ *val = !!(data->fan_config[channel] & MAX31790_FAN_CFG_TACH_INPUT_EN);
+ return 0;
+ case hwmon_fan_div:
+ *val = get_tach_period(data->fan_config[channel]);
return 0;
default:
return -EOPNOTSUPP;
@@ -191,7 +235,7 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel,
long val)
{
struct max31790_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
+ struct regmap *regmap = data->regmap;
int target_count;
int err = 0;
u8 bits;
@@ -207,9 +251,10 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel,
((data->fan_dynamics[channel] &
~MAX31790_FAN_DYN_SR_MASK) |
(bits << MAX31790_FAN_DYN_SR_SHIFT));
- err = i2c_smbus_write_byte_data(client,
- MAX31790_REG_FAN_DYNAMICS(channel),
- data->fan_dynamics[channel]);
+
+ err = regmap_write(regmap,
+ MAX31790_REG_FAN_DYNAMICS(channel),
+ data->fan_dynamics[channel]);
if (err < 0)
break;
@@ -217,11 +262,38 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel,
target_count = RPM_TO_REG(val, sr);
target_count = clamp_val(target_count, 0x1, 0x7FF);
- data->target_count[channel] = target_count << 5;
+ target_count = target_count << 5;
- err = i2c_smbus_write_word_swapped(client,
- MAX31790_REG_TARGET_COUNT(channel),
- data->target_count[channel]);
+ err = write_reg_word(regmap,
+ MAX31790_REG_TARGET_COUNT(channel),
+ target_count);
+ break;
+ case hwmon_fan_enable:
+ if (val == 0)
+ data->fan_config[channel] &= ~MAX31790_FAN_CFG_TACH_INPUT_EN;
+ else
+ data->fan_config[channel] |= MAX31790_FAN_CFG_TACH_INPUT_EN;
+ err = regmap_write(regmap,
+ MAX31790_REG_FAN_CONFIG(channel),
+ data->fan_config[channel]);
+ break;
+ case hwmon_fan_div:
+ if (data->fan_config[channel] & MAX31790_FAN_CFG_RPM_MODE) {
+ err = -EINVAL;
+ break;
+ }
+ sr = bits_for_speed_range(val);
+ if (sr < 0) {
+ err = -EINVAL;
+ break;
+ }
+
+ data->fan_dynamics[channel] = ((data->fan_dynamics[channel] &
+ ~MAX31790_FAN_DYN_SR_MASK) |
+ (sr << MAX31790_FAN_DYN_SR_SHIFT));
+ err = regmap_write(regmap,
+ MAX31790_REG_FAN_DYNAMICS(channel),
+ data->fan_dynamics[channel]);
break;
default:
err = -EOPNOTSUPP;
@@ -250,6 +322,12 @@ static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel)
!(fan_config & MAX31790_FAN_CFG_TACH_INPUT))
return 0644;
return 0;
+ case hwmon_fan_enable:
+ case hwmon_fan_div:
+ if (channel < NR_CHANNEL ||
+ (fan_config & MAX31790_FAN_CFG_TACH_INPUT))
+ return 0644;
+ return 0;
default:
return 0;
}
@@ -258,25 +336,25 @@ static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel)
static int max31790_read_pwm(struct device *dev, u32 attr, int channel,
long *val)
{
- struct max31790_data *data = max31790_update_device(dev);
- u8 fan_config;
-
- if (IS_ERR(data))
- return PTR_ERR(data);
-
- fan_config = data->fan_config[channel];
+ struct max31790_data *data = dev_get_drvdata(dev);
+ struct regmap *regmap = data->regmap;
+ int read;
switch (attr) {
case hwmon_pwm_input:
- *val = data->pwm[channel] >> 8;
+ read = read_reg_word(regmap, MAX31790_REG_PWMOUT(channel));
+ if (read < 0)
+ return read;
+
+ *val = read >> 8;
return 0;
case hwmon_pwm_enable:
- if (fan_config & MAX31790_FAN_CFG_RPM_MODE)
+ if (data->fan_config[channel] & MAX31790_FAN_CFG_CTRL_MON)
+ *val = 0;
+ else if (data->fan_config[channel] & MAX31790_FAN_CFG_RPM_MODE)
*val = 2;
- else if (fan_config & MAX31790_FAN_CFG_TACH_INPUT_EN)
+ else
*val = 1;
- else
- *val = 0;
return 0;
default:
return -EOPNOTSUPP;
@@ -287,43 +365,46 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel,
long val)
{
struct max31790_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
- u8 fan_config;
+ struct regmap *regmap = data->regmap;
+ u8 fan_config = data->fan_config[channel];
int err = 0;
mutex_lock(&data->update_lock);
switch (attr) {
case hwmon_pwm_input:
- if (val < 0 || val > 255) {
+ if (fan_config & MAX31790_FAN_CFG_CTRL_MON || val < 0 || val > 255) {
err = -EINVAL;
break;
}
- data->pwm[channel] = val << 8;
- err = i2c_smbus_write_word_swapped(client,
- MAX31790_REG_PWMOUT(channel),
- data->pwm[channel]);
+
+ err = write_reg_word(regmap, MAX31790_REG_PWMOUT(channel), val << 8);
break;
case hwmon_pwm_enable:
fan_config = data->fan_config[channel];
- if (val == 0) {
- fan_config &= ~(MAX31790_FAN_CFG_TACH_INPUT_EN |
- MAX31790_FAN_CFG_RPM_MODE);
- } else if (val == 1) {
- fan_config = (fan_config |
- MAX31790_FAN_CFG_TACH_INPUT_EN) &
- ~MAX31790_FAN_CFG_RPM_MODE;
+ if (val == 0)
+ fan_config |= MAX31790_FAN_CFG_CTRL_MON;
+ else if (val == 1) {
+ fan_config &= ~(MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_CTRL_MON);
} else if (val == 2) {
- fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN |
- MAX31790_FAN_CFG_RPM_MODE;
+ fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON);
+ fan_config |= MAX31790_FAN_CFG_RPM_MODE;
} else {
err = -EINVAL;
break;
}
+
+ /*
+ * RPM mode implies enabled TACH input, so enable it in RPM
+ * mode.
+ */
+ if (val == 2)
+ fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN;
+
data->fan_config[channel] = fan_config;
- err = i2c_smbus_write_byte_data(client,
- MAX31790_REG_FAN_CONFIG(channel),
- fan_config);
+ err = regmap_write(regmap,
+ MAX31790_REG_FAN_CONFIG(channel),
+ fan_config);
break;
default:
err = -EOPNOTSUPP;
@@ -393,18 +474,18 @@ static umode_t max31790_is_visible(const void *data,
static const struct hwmon_channel_info *max31790_info[] = {
HWMON_CHANNEL_INFO(fan,
- HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_FAULT,
- HWMON_F_INPUT | HWMON_F_FAULT),
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT,
+ HWMON_F_DIV | HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT),
HWMON_CHANNEL_INFO(pwm,
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
@@ -426,20 +507,18 @@ static const struct hwmon_chip_info max31790_chip_info = {
.info = max31790_info,
};
-static int max31790_init_client(struct i2c_client *client,
+static int max31790_init_client(struct regmap *regmap,
struct max31790_data *data)
{
int i, rv;
for (i = 0; i < NR_CHANNEL; i++) {
- rv = i2c_smbus_read_byte_data(client,
- MAX31790_REG_FAN_CONFIG(i));
+ rv = read_reg_byte(regmap, MAX31790_REG_FAN_CONFIG(i % NR_CHANNEL));
if (rv < 0)
return rv;
data->fan_config[i] = rv;
- rv = i2c_smbus_read_byte_data(client,
- MAX31790_REG_FAN_DYNAMICS(i));
+ rv = read_reg_byte(regmap, MAX31790_REG_FAN_DYNAMICS(i));
if (rv < 0)
return rv;
data->fan_dynamics[i] = rv;
@@ -464,13 +543,18 @@ static int max31790_probe(struct i2c_client *client)
if (!data)
return -ENOMEM;
- data->client = client;
mutex_init(&data->update_lock);
+ data->regmap = devm_regmap_init_i2c(client, &max31790_regmap_config);
+ if (IS_ERR(data->regmap)) {
+ dev_err(dev, "failed to allocate register map\n");
+ return PTR_ERR(data->regmap);
+ }
+
/*
* Initialize the max31790 chip
*/
- err = max31790_init_client(client, data);
+ err = max31790_init_client(data->regmap, data);
if (err)
return err;
@@ -488,11 +572,18 @@ static const struct i2c_device_id max31790_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max31790_id);
+static const struct of_device_id __maybe_unused max31790_of_match[] = {
+ { .compatible = "maxim,max31790" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max31790_of_match);
+
static struct i2c_driver max31790_driver = {
.class = I2C_CLASS_HWMON,
.probe_new = max31790_probe,
.driver = {
.name = "max31790",
+ .of_match_table = of_match_ptr(max31790_of_match),
},
.id_table = max31790_id,
};
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 32d2fc850621..5ec5b3bd1986 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -56,6 +56,16 @@ config SENSORS_BEL_PFE
This driver can also be built as a module. If so, the module will
be called bel-pfe.
+config SENSORS_FSP_3Y
+ tristate "FSP/3Y-Power power supplies"
+ help
+ If you say yes here you get hardware monitoring support for
+ FSP/3Y-Power hot-swap power supplies.
+ Supported models: YH-5151E, YM-2151E
+
+ This driver can also be built as a module. If so, the module will
+ be called fsp-3y.
+
config SENSORS_IBM_CFFPS
tristate "IBM Common Form Factor Power Supply"
depends on LEDS_CLASS
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index 6a4ba0fdc1db..bfe218ad898f 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
obj-$(CONFIG_SENSORS_ADM1266) += adm1266.o
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_BEL_PFE) += bel-pfe.o
+obj-$(CONFIG_SENSORS_FSP_3Y) += fsp-3y.o
obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o
obj-$(CONFIG_SENSORS_INSPUR_IPSPS) += inspur-ipsps.o
obj-$(CONFIG_SENSORS_IR35221) += ir35221.o
diff --git a/drivers/hwmon/pmbus/fsp-3y.c b/drivers/hwmon/pmbus/fsp-3y.c
new file mode 100644
index 000000000000..073d960a0af5
--- /dev/null
+++ b/drivers/hwmon/pmbus/fsp-3y.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware monitoring driver for FSP 3Y-Power PSUs
+ *
+ * Copyright (c) 2021 Václav Kubernát, CESNET
+ *
+ * This driver is mostly reverse engineered with the help of a tool called pmbus_peek written by
+ * David Brownell (and later adopted by Jan Kundrát). The device has some sort of a timing issue
+ * when switching pages, details are explained in the code. The driver support is limited. It
+ * exposes only the values, that have been tested to work correctly. Unsupported values either
+ * aren't supported by the devices or their encondings are unknown.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+#define YM2151_PAGE_12V_LOG 0x00
+#define YM2151_PAGE_12V_REAL 0x00
+#define YM2151_PAGE_5VSB_LOG 0x01
+#define YM2151_PAGE_5VSB_REAL 0x20
+#define YH5151E_PAGE_12V_LOG 0x00
+#define YH5151E_PAGE_12V_REAL 0x00
+#define YH5151E_PAGE_5V_LOG 0x01
+#define YH5151E_PAGE_5V_REAL 0x10
+#define YH5151E_PAGE_3V3_LOG 0x02
+#define YH5151E_PAGE_3V3_REAL 0x11
+
+enum chips {
+ ym2151e,
+ yh5151e
+};
+
+struct fsp3y_data {
+ struct pmbus_driver_info info;
+ int chip;
+ int page;
+
+ bool vout_linear_11;
+};
+
+#define to_fsp3y_data(x) container_of(x, struct fsp3y_data, info)
+
+static int page_log_to_page_real(int page_log, enum chips chip)
+{
+ switch (chip) {
+ case ym2151e:
+ switch (page_log) {
+ case YM2151_PAGE_12V_LOG:
+ return YM2151_PAGE_12V_REAL;
+ case YM2151_PAGE_5VSB_LOG:
+ return YM2151_PAGE_5VSB_REAL;
+ }
+ return -EINVAL;
+ case yh5151e:
+ switch (page_log) {
+ case YH5151E_PAGE_12V_LOG:
+ return YH5151E_PAGE_12V_REAL;
+ case YH5151E_PAGE_5V_LOG:
+ return YH5151E_PAGE_5V_REAL;
+ case YH5151E_PAGE_3V3_LOG:
+ return YH5151E_PAGE_3V3_REAL;
+ }
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+
+static int set_page(struct i2c_client *client, int page_log)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct fsp3y_data *data = to_fsp3y_data(info);
+ int rv;
+ int page_real;
+
+ if (page_log < 0)
+ return 0;
+
+ page_real = page_log_to_page_real(page_log, data->chip);
+ if (page_real < 0)
+ return page_real;
+
+ if (data->page != page_real) {
+ rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page_real);
+ if (rv < 0)
+ return rv;
+
+ data->page = page_real;
+
+ /*
+ * Testing showed that the device has a timing issue. After
+ * setting a page, it takes a while, before the device actually
+ * gives the correct values from the correct page. 20 ms was
+ * tested to be enough to not give wrong values (15 ms wasn't
+ * enough).
+ */
+ usleep_range(20000, 30000);
+ }
+
+ return 0;
+}
+
+static int fsp3y_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct fsp3y_data *data = to_fsp3y_data(info);
+ int rv;
+
+ /*
+ * Inject an exponent for non-compliant YH5151-E.
+ */
+ if (data->vout_linear_11 && reg == PMBUS_VOUT_MODE)
+ return 0x1A;
+
+ rv = set_page(client, page);
+ if (rv < 0)
+ return rv;
+
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int fsp3y_read_word_data(struct i2c_client *client, int page, int phase, int reg)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ struct fsp3y_data *data = to_fsp3y_data(info);
+ int rv;
+
+ /*
+ * This masks commands which weren't tested to work correctly. Some of
+ * the masked commands return 0xFFFF. These would probably get tagged as
+ * invalid by pmbus_core. Other ones do return values which might be
+ * useful (that is, they are not 0xFFFF), but their encoding is unknown,
+ * and so they are unsupported.
+ */
+ switch (reg) {
+ case PMBUS_READ_FAN_SPEED_1:
+ case PMBUS_READ_IIN:
+ case PMBUS_READ_IOUT:
+ case PMBUS_READ_PIN:
+ case PMBUS_READ_POUT:
+ case PMBUS_READ_TEMPERATURE_1:
+ case PMBUS_READ_TEMPERATURE_2:
+ case PMBUS_READ_TEMPERATURE_3:
+ case PMBUS_READ_VIN:
+ case PMBUS_READ_VOUT:
+ case PMBUS_STATUS_WORD:
+ break;
+ default:
+ return -ENXIO;
+ }
+
+ rv = set_page(client, page);
+ if (rv < 0)
+ return rv;
+
+ rv = i2c_smbus_read_word_data(client, reg);
+ if (rv < 0)
+ return rv;
+
+ /*
+ * Handle YH-5151E non-compliant linear11 vout voltage.
+ */
+ if (data->vout_linear_11 && reg == PMBUS_READ_VOUT)
+ rv = sign_extend32(rv, 10) & 0xffff;
+
+ return rv;
+}
+
+static struct pmbus_driver_info fsp3y_info[] = {
+ [ym2151e] = {
+ .pages = 2,
+ .func[YM2151_PAGE_12V_LOG] =
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_PIN | PMBUS_HAVE_POUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 |
+ PMBUS_HAVE_VIN | PMBUS_HAVE_IIN |
+ PMBUS_HAVE_FAN12,
+ .func[YM2151_PAGE_5VSB_LOG] =
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT,
+ PMBUS_HAVE_IIN,
+ .read_word_data = fsp3y_read_word_data,
+ .read_byte_data = fsp3y_read_byte_data,
+ },
+ [yh5151e] = {
+ .pages = 3,
+ .func[YH5151E_PAGE_12V_LOG] =
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_POUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3,
+ .func[YH5151E_PAGE_5V_LOG] =
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_POUT,
+ .func[YH5151E_PAGE_3V3_LOG] =
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
+ PMBUS_HAVE_POUT,
+ .read_word_data = fsp3y_read_word_data,
+ .read_byte_data = fsp3y_read_byte_data,
+ }
+};
+
+static int fsp3y_detect(struct i2c_client *client)
+{
+ int rv;
+ u8 buf[I2C_SMBUS_BLOCK_MAX + 1];
+
+ rv = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
+ if (rv < 0)
+ return rv;
+
+ buf[rv] = '\0';
+
+ if (rv == 8) {
+ if (!strcmp(buf, "YM-2151E"))
+ return ym2151e;
+ else if (!strcmp(buf, "YH-5151E"))
+ return yh5151e;
+ }
+
+ dev_err(&client->dev, "Unsupported model %.*s\n", rv, buf);
+ return -ENODEV;
+}
+
+static const struct i2c_device_id fsp3y_id[] = {
+ {"ym2151e", ym2151e},
+ {"yh5151e", yh5151e},
+ { }
+};
+
+static int fsp3y_probe(struct i2c_client *client)
+{
+ struct fsp3y_data *data;
+ const struct i2c_device_id *id;
+ int rv;
+
+ data = devm_kzalloc(&client->dev, sizeof(struct fsp3y_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->chip = fsp3y_detect(client);
+ if (data->chip < 0)
+ return data->chip;
+
+ id = i2c_match_id(fsp3y_id, client);
+ if (data->chip != id->driver_data)
+ dev_warn(&client->dev, "Device mismatch: Configured %s (%d), detected %d\n",
+ id->name, (int)id->driver_data, data->chip);
+
+ rv = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
+ if (rv < 0)
+ return rv;
+ data->page = rv;
+
+ data->info = fsp3y_info[data->chip];
+
+ /*
+ * YH-5151E sometimes reports vout in linear11 and sometimes in
+ * linear16. This depends on the exact individual piece of hardware. One
+ * YH-5151E can use linear16 and another might use linear11 instead.
+ *
+ * The format can be recognized by reading VOUT_MODE - if it doesn't
+ * report a valid exponent, then vout uses linear11. Otherwise, the
+ * device is compliant and uses linear16.
+ */
+ data->vout_linear_11 = false;
+ if (data->chip == yh5151e) {
+ rv = i2c_smbus_read_byte_data(client, PMBUS_VOUT_MODE);
+ if (rv < 0)
+ return rv;
+
+ if (rv == 0xFF)
+ data->vout_linear_11 = true;
+ }
+
+ return pmbus_do_probe(client, &data->info);
+}
+
+MODULE_DEVICE_TABLE(i2c, fsp3y_id);
+
+static struct i2c_driver fsp3y_driver = {
+ .driver = {
+ .name = "fsp3y",
+ },
+ .probe_new = fsp3y_probe,
+ .id_table = fsp3y_id
+};
+
+module_i2c_driver(fsp3y_driver);
+
+MODULE_AUTHOR("Václav Kubernát");
+MODULE_DESCRIPTION("PMBus driver for FSP/3Y-Power power supplies");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c
index 5b9dfdf743ec..26ea1164cb49 100644
--- a/drivers/leds/leds-tlc591xx.c
+++ b/drivers/leds/leds-tlc591xx.c
@@ -40,6 +40,9 @@
#define ldev_to_led(c) container_of(c, struct tlc591xx_led, ldev)
+#define TLC591XX_RESET_BYTE_0 0xa5
+#define TLC591XX_RESET_BYTE_1 0x5a
+
struct tlc591xx_led {
bool active;
unsigned int led_no;
@@ -51,21 +54,25 @@ struct tlc591xx_priv {
struct tlc591xx_led leds[TLC591XX_MAX_LEDS];
struct regmap *regmap;
unsigned int reg_ledout_offset;
+ struct i2c_client *swrst_client;
};
struct tlc591xx {
unsigned int max_leds;
unsigned int reg_ledout_offset;
+ u8 swrst_addr;
};
static const struct tlc591xx tlc59116 = {
.max_leds = 16,
.reg_ledout_offset = 0x14,
+ .swrst_addr = 0x6b,
};
static const struct tlc591xx tlc59108 = {
.max_leds = 8,
.reg_ledout_offset = 0x0c,
+ .swrst_addr = 0x4b,
};
static int
@@ -176,6 +183,18 @@ tlc591xx_probe(struct i2c_client *client,
i2c_set_clientdata(client, priv);
+ priv->swrst_client = devm_i2c_new_dummy_device(dev, client->adapter, tlc591xx->swrst_addr);
+ if (IS_ERR(priv->swrst_client)) {
+ dev_info(dev, "Skipping reset: address %02x already used\n",
+ tlc591xx->swrst_addr);
+ } else {
+ err = i2c_smbus_write_byte_data(priv->swrst_client,
+ TLC591XX_RESET_BYTE_0, TLC591XX_RESET_BYTE_1);
+ if (err) {
+ dev_warn(dev, "SW reset failed\n");
+ }
+ }
+
err = tlc591xx_set_mode(priv->regmap, MODE2_DIM);
if (err < 0)
return err;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index a45cd2b416c8..aa4c38a0952d 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -577,16 +577,15 @@ static void igb_set_i2c_data(void *data, int state)
struct e1000_hw *hw = &adapter->hw;
s32 i2cctl = rd32(E1000_I2CPARAMS);
- if (state)
- i2cctl |= E1000_I2C_DATA_OUT;
- else
+ if (state) {
+ i2cctl |= E1000_I2C_DATA_OUT | E1000_I2C_DATA_OE_N;
+ } else {
+ i2cctl &= ~E1000_I2C_DATA_OE_N;
i2cctl &= ~E1000_I2C_DATA_OUT;
+ }
- i2cctl &= ~E1000_I2C_DATA_OE_N;
- i2cctl |= E1000_I2C_CLK_OE_N;
wr32(E1000_I2CPARAMS, i2cctl);
wrfl();
-
}
/**
@@ -603,8 +602,7 @@ static void igb_set_i2c_clk(void *data, int state)
s32 i2cctl = rd32(E1000_I2CPARAMS);
if (state) {
- i2cctl |= E1000_I2C_CLK_OUT;
- i2cctl &= ~E1000_I2C_CLK_OE_N;
+ i2cctl |= E1000_I2C_CLK_OUT | E1000_I2C_CLK_OE_N;
} else {
i2cctl &= ~E1000_I2C_CLK_OUT;
i2cctl &= ~E1000_I2C_CLK_OE_N;
@@ -3109,11 +3107,20 @@ static void igb_init_mas(struct igb_adapter *adapter)
static s32 igb_init_i2c(struct igb_adapter *adapter)
{
s32 status = 0;
+ s32 i2cctl;
+ struct e1000_hw *hw = &adapter->hw;
/* I2C interface supported on i350 devices */
if (adapter->hw.mac.type != e1000_i350)
return 0;
+ i2cctl = rd32(E1000_I2CPARAMS);
+ i2cctl |= E1000_I2CBB_EN
+ | E1000_I2C_CLK_OUT | E1000_I2C_CLK_OE_N
+ | E1000_I2C_DATA_OUT | E1000_I2C_DATA_OE_N;
+ wr32(E1000_I2CPARAMS, i2cctl);
+ wrfl();
+
/* Initialize the i2c bus which is controlled by the registers.
* This bus will use the i2c_algo_bit structue that implements
* the protocol through toggling of the 4 bits in the register.
diff --git a/drivers/pinctrl/pinctrl-mcp23s08_spi.c b/drivers/pinctrl/pinctrl-mcp23s08_spi.c
index 9ae10318f6f3..d378369bbeca 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08_spi.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08_spi.c
@@ -8,6 +8,7 @@
#include <linux/spi/spi.h>
#include "pinctrl-mcp23s08.h"
+#include "../gpio/gpiolib.h"
#define MCP_MAX_DEV_PER_CS 8
@@ -143,6 +144,10 @@ static int mcp23s08_probe(struct spi_device *spi)
int type;
int ret;
u32 v;
+ struct device_node *np;
+ int line_name_count;
+ const char **names;
+ int i;
match = device_get_match_data(dev);
if (match)
@@ -192,6 +197,43 @@ static int mcp23s08_probe(struct spi_device *spi)
return ret;
ngpio += data->mcp[addr]->chip.ngpio;
+
+ for_each_available_child_of_node(spi->dev.of_node, np) {
+ u32 chip_addr;
+ ret = of_property_read_u32(np, "address", &chip_addr);
+ if (ret)
+ continue;
+ if (chip_addr != addr)
+ continue;
+
+ line_name_count = fwnode_property_read_string_array(of_fwnode_handle(np), "gpio-line-names", NULL, 0);
+ if (line_name_count < 0)
+ continue;
+
+ if (line_name_count > data->mcp[addr]->chip.ngpio) {
+ dev_warn(&spi->dev, "gpio-line-names is length %d but should be at most length %d",
+ line_name_count, data->mcp[addr]->chip.ngpio);
+ line_name_count = data->mcp[addr]->chip.ngpio;
+ }
+
+ names = kcalloc(line_name_count, sizeof(*names), GFP_KERNEL);
+ if (!names) {
+ dev_warn(&spi->dev, "cannot allocate gpio-line-names");
+ continue;
+ }
+
+ ret = fwnode_property_read_string_array(of_fwnode_handle(np), "gpio-line-names", names, line_name_count);
+ if (ret < 0) {
+ dev_warn(&spi->dev, "failed to read GPIO line names");
+ kfree(names);
+ continue;
+ }
+
+ for (i = 0; i < line_name_count; i++)
+ data->mcp[addr]->chip.gpiodev->descs[i].name = names[i];
+
+ kfree(names);
+ }
}
data->ngpio = ngpio;
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 68ed7fd64256..3fd04d5eeb14 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -86,10 +86,6 @@ struct orion_direct_acc {
u32 size;
};
-struct orion_child_options {
- struct orion_direct_acc direct_access;
-};
-
struct orion_spi {
struct spi_master *master;
void __iomem *base;
@@ -98,7 +94,7 @@ struct orion_spi {
const struct orion_spi_dev *devdata;
struct device *dev;
- struct orion_child_options child[ORION_NUM_CHIPSELECTS];
+ struct orion_direct_acc direct_access[ORION_NUM_CHIPSELECTS];
};
#ifdef CONFIG_PM
@@ -463,7 +459,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
int cs = spi->chip_select;
void __iomem *vaddr;
- word_len = spi->bits_per_word;
+ word_len = xfer->bits_per_word;
count = xfer->len;
orion_spi = spi_master_get_devdata(spi->master);
@@ -473,7 +469,7 @@ orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
* and SPI_CS_WORD flag is not set.
* Otherwise fall back to PIO mode for this transfer.
*/
- vaddr = orion_spi->child[cs].direct_access.vaddr;
+ vaddr = orion_spi->direct_access[cs].vaddr;
if (vaddr && xfer->tx_buf && word_len == 8 && (spi->mode & SPI_CS_WORD) == 0) {
unsigned int cnt = count / 4;
@@ -727,7 +723,6 @@ static int orion_spi_probe(struct platform_device *pdev)
}
for_each_available_child_of_node(pdev->dev.of_node, np) {
- struct orion_direct_acc *dir_acc;
u32 cs;
/* Get chip-select number from the "reg" property */
@@ -756,13 +751,14 @@ static int orion_spi_probe(struct platform_device *pdev)
* This needs to get extended for the direct SPI NOR / SPI NAND
* support, once this gets implemented.
*/
- dir_acc = &spi->child[cs].direct_access;
- dir_acc->vaddr = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE);
- if (!dir_acc->vaddr) {
+ spi->direct_access[cs].vaddr = devm_ioremap(&pdev->dev,
+ r->start,
+ PAGE_SIZE);
+ if (!spi->direct_access[cs].vaddr) {
status = -ENOMEM;
goto out_rel_axi_clk;
}
- dir_acc->size = PAGE_SIZE;
+ spi->direct_access[cs].size = PAGE_SIZE;
dev_info(&pdev->dev, "CS%d configured for direct access\n", cs);
}
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 1b61d26bb7af..e92f3c02c7f4 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -235,6 +235,10 @@
#define MAX310x_REV_MASK (0xf8)
#define MAX310X_WRITE_BIT 0x80
+/* Timeout for external crystal stability */
+#define MAX310X_XTAL_WAIT_RETRIES 20
+#define MAX310X_XTAL_WAIT_DELAY_MS 10
+
/* MAX3107 specific */
#define MAX3107_REV_ID (0xa0)
@@ -610,11 +614,14 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
/* Wait for crystal */
if (xtal) {
- unsigned int val;
- msleep(10);
- regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &val);
+ unsigned int val = 0, i;
+ for (i = 0; i < MAX310X_XTAL_WAIT_RETRIES && !(val & MAX310X_STS_CLKREADY_BIT); ++i) {
+ msleep(MAX310X_XTAL_WAIT_DELAY_MS);
+ regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &val);
+ }
if (!(val & MAX310X_STS_CLKREADY_BIT)) {
- dev_warn(dev, "clock is not stable yet\n");
+ dev_err(dev, "clock is not stable\n");
+ return -EAGAIN;
}
}
@@ -1327,6 +1334,10 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
}
uartclk = max310x_set_ref_clk(dev, s, freq, xtal);
+ if (uartclk < 0) {
+ ret = uartclk;
+ goto out_uart;
+ }
dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
for (i = 0; i < devtype->nr; i++) {