mirror of
https://github.com/Telecominfraproject/OpenNetworkLinux.git
synced 2026-01-27 10:22:15 +00:00
Initial framework for 4.19.
This commit is contained in:
3
packages/base/any/kernels/4.19-lts/configs/x86_64-all/.gitignore
vendored
Normal file
3
packages/base/any/kernels/4.19-lts/configs/x86_64-all/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
kernel-*
|
||||
linux-*
|
||||
lib
|
||||
@@ -0,0 +1,37 @@
|
||||
############################################################
|
||||
# <bsn.cl fy=2015 v=onl>
|
||||
#
|
||||
# Copyright 2015 Big Switch Networks, Inc.
|
||||
#
|
||||
# Licensed under the Eclipse Public License, Version 1.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
# either express or implied. See the License for the specific
|
||||
# language governing permissions and limitations under the
|
||||
# License.
|
||||
#
|
||||
# </bsn.cl>
|
||||
############################################################
|
||||
THIS_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
|
||||
include $(ONL)/make/config.mk
|
||||
|
||||
export ARCH := x86_64
|
||||
ifndef K_TARGET_DIR
|
||||
K_TARGET_DIR := $(THIS_DIR)
|
||||
endif
|
||||
|
||||
include ../../kconfig.mk
|
||||
K_CONFIG := x86_64-all.config
|
||||
K_BUILD_TARGET := bzImage
|
||||
K_COPY_SRC := arch/x86/boot/bzImage
|
||||
ifndef K_COPY_DST
|
||||
K_COPY_DST := kernel-4.19-lts-x86_64-all
|
||||
endif
|
||||
|
||||
include $(ONL)/make/kbuild.mk
|
||||
4392
packages/base/any/kernels/4.19-lts/configs/x86_64-all/x86_64-all.config
Executable file
4392
packages/base/any/kernels/4.19-lts/configs/x86_64-all/x86_64-all.config
Executable file
File diff suppressed because it is too large
Load Diff
27
packages/base/any/kernels/4.19-lts/kconfig.mk
Normal file
27
packages/base/any/kernels/4.19-lts/kconfig.mk
Normal file
@@ -0,0 +1,27 @@
|
||||
############################################################
|
||||
# <bsn.cl fy=2015 v=onl>
|
||||
#
|
||||
# Copyright 2015 Big Switch Networks, Inc.
|
||||
#
|
||||
# Licensed under the Eclipse Public License, Version 1.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
# either express or implied. See the License for the specific
|
||||
# language governing permissions and limitations under the
|
||||
# License.
|
||||
#
|
||||
# </bsn.cl>
|
||||
############################################################
|
||||
THIS_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
|
||||
K_MAJOR_VERSION := 4
|
||||
K_PATCH_LEVEL := 19
|
||||
K_SUB_LEVEL := 58
|
||||
K_SUFFIX :=
|
||||
K_PATCH_DIR := $(THIS_DIR)/patches
|
||||
K_MODSYNCLIST := tools/objtool
|
||||
@@ -0,0 +1,34 @@
|
||||
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
|
||||
index 0f5c8fc..f93099c 100644
|
||||
--- a/drivers/i2c/muxes/Kconfig
|
||||
+++ b/drivers/i2c/muxes/Kconfig
|
||||
@@ -73,6 +73,13 @@ config I2C_MUX_PCA954x
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-mux-pca954x.
|
||||
|
||||
+config I2C_MUX_PCA954X_DESELECT_ON_EXIT
|
||||
+ bool "Enable deselect-on-exit feature for PCA954X devices."
|
||||
+ depends on I2C_MUX_PCA954x
|
||||
+ help
|
||||
+ If you say yes here you enable the deselect-on-exit feature in
|
||||
+ the pca954x i2c driver.
|
||||
+
|
||||
config I2C_MUX_PINCTRL
|
||||
tristate "pinctrl-based I2C multiplexer"
|
||||
depends on PINCTRL
|
||||
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
|
||||
index 7b992db..bdca051 100644
|
||||
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
|
||||
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
|
||||
@@ -218,8 +218,10 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
|
||||
struct pca954x *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
|
||||
+#if !defined(CONFIG_I2C_MUX_PCA954X_DESELECT_ON_EXIT)
|
||||
if (!(data->deselect & (1 << chan)))
|
||||
return 0;
|
||||
+#endif
|
||||
|
||||
/* Deselect active channel */
|
||||
data->last_chan = 0;
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
|
||||
index c37cc8b..41c0ff2 100644
|
||||
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
|
||||
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
|
||||
@@ -340,6 +340,12 @@ static s32 igb_init_phy_params_82575(struct e1000_hw *hw)
|
||||
phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_82580;
|
||||
phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88;
|
||||
break;
|
||||
+ case BCM5461S_PHY_ID:
|
||||
+ phy->type = e1000_phy_bcm5461s;
|
||||
+ phy->ops.check_polarity = NULL;
|
||||
+ phy->ops.get_cable_length = NULL;
|
||||
+ phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_82580;
|
||||
+ break;
|
||||
case BCM54616_E_PHY_ID:
|
||||
phy->type = e1000_phy_bcm54616;
|
||||
break;
|
||||
@@ -902,6 +908,16 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
|
||||
goto out;
|
||||
}
|
||||
ret_val = igb_get_phy_id(hw);
|
||||
+ if (ret_val && hw->mac.type == e1000_i354) {
|
||||
+ /* we do a special check for bcm5461s phy by setting
|
||||
+ * the phy->addr to 5 and doing the phy check again. This
|
||||
+ * call will succeed and retrieve a valid phy id if we have
|
||||
+ * the bcm5461s phy
|
||||
+ */
|
||||
+ phy->addr = 5;
|
||||
+ phy->type = e1000_phy_bcm5461s;
|
||||
+ ret_val = igb_get_phy_id(hw);
|
||||
+ }
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1289,6 +1305,9 @@ static s32 igb_get_cfg_done_82575(struct e1000_hw *hw)
|
||||
(hw->phy.type == e1000_phy_igp_3))
|
||||
igb_phy_init_script_igp3(hw);
|
||||
|
||||
+ if (hw->phy.type == e1000_phy_bcm5461s)
|
||||
+ igb_phy_init_script_5461s(hw);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1618,6 +1637,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
|
||||
case e1000_i350:
|
||||
case e1000_i210:
|
||||
case e1000_i211:
|
||||
+ case e1000_i354:
|
||||
phpm_reg = rd32(E1000_82580_PHY_POWER_MGMT);
|
||||
phpm_reg &= ~E1000_82580_PM_GO_LINKD;
|
||||
wr32(E1000_82580_PHY_POWER_MGMT, phpm_reg);
|
||||
@@ -1663,7 +1683,8 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
|
||||
ret_val = igb_copper_link_setup_82580(hw);
|
||||
break;
|
||||
case e1000_phy_bcm54616:
|
||||
- ret_val = 0;
|
||||
+ break;
|
||||
+ case e1000_phy_bcm5461s:
|
||||
break;
|
||||
default:
|
||||
ret_val = -E1000_ERR_PHY;
|
||||
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
|
||||
index 1de82f2..0703c3e 100644
|
||||
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
|
||||
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
|
||||
@@ -890,6 +890,7 @@
|
||||
#define M88E1543_E_PHY_ID 0x01410EA0
|
||||
#define M88E1512_E_PHY_ID 0x01410DD0
|
||||
#define BCM54616_E_PHY_ID 0x03625D10
|
||||
+#define BCM5461S_PHY_ID 0x002060C0
|
||||
|
||||
/* M88E1000 Specific Registers */
|
||||
#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
|
||||
diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h
|
||||
index 6c9485a..2a0b83b 100644
|
||||
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h
|
||||
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h
|
||||
@@ -129,6 +129,7 @@ enum e1000_phy_type {
|
||||
e1000_phy_82580,
|
||||
e1000_phy_i210,
|
||||
e1000_phy_bcm54616,
|
||||
+ e1000_phy_bcm5461s,
|
||||
};
|
||||
|
||||
enum e1000_bus_type {
|
||||
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c
|
||||
index 413025b..4c2a5ff 100644
|
||||
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
|
||||
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
|
||||
@@ -146,6 +146,13 @@ s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
|
||||
* Control register. The MAC will take care of interfacing with the
|
||||
* PHY to retrieve the desired data.
|
||||
*/
|
||||
+ if (phy->type == e1000_phy_bcm5461s) {
|
||||
+ mdic = rd32(E1000_MDICNFG);
|
||||
+ mdic &= ~E1000_MDICNFG_PHY_MASK;
|
||||
+ mdic |= (phy->addr << E1000_MDICNFG_PHY_SHIFT);
|
||||
+ wr32(E1000_MDICNFG, mdic);
|
||||
+ }
|
||||
+
|
||||
mdic = ((offset << E1000_MDIC_REG_SHIFT) |
|
||||
(phy->addr << E1000_MDIC_PHY_SHIFT) |
|
||||
(E1000_MDIC_OP_READ));
|
||||
@@ -202,6 +209,13 @@ s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
|
||||
* Control register. The MAC will take care of interfacing with the
|
||||
* PHY to retrieve the desired data.
|
||||
*/
|
||||
+ if (phy->type == e1000_phy_bcm5461s) {
|
||||
+ mdic = rd32(E1000_MDICNFG);
|
||||
+ mdic &= ~E1000_MDICNFG_PHY_MASK;
|
||||
+ mdic |= (phy->addr << E1000_MDICNFG_PHY_SHIFT);
|
||||
+ wr32(E1000_MDICNFG, mdic);
|
||||
+ }
|
||||
+
|
||||
mdic = (((u32)data) |
|
||||
(offset << E1000_MDIC_REG_SHIFT) |
|
||||
(phy->addr << E1000_MDIC_PHY_SHIFT) |
|
||||
@@ -1113,11 +1127,13 @@ s32 igb_setup_copper_link(struct e1000_hw *hw)
|
||||
* depending on user settings.
|
||||
*/
|
||||
hw_dbg("Forcing Speed and Duplex\n");
|
||||
- ret_val = hw->phy.ops.force_speed_duplex(hw);
|
||||
- if (ret_val) {
|
||||
- hw_dbg("Error Forcing Speed and Duplex\n");
|
||||
- goto out;
|
||||
- }
|
||||
+ if (hw->phy.ops.force_speed_duplex) {
|
||||
+ ret_val = hw->phy.ops.force_speed_duplex(hw);
|
||||
+ if (ret_val) {
|
||||
+ hw_dbg("Error Forcing Speed and Duplex\n");
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
/* Check link status. Wait up to 100 microseconds for link to become
|
||||
@@ -2647,3 +2663,66 @@ static s32 igb_set_master_slave_mode(struct e1000_hw *hw)
|
||||
|
||||
return hw->phy.ops.write_reg(hw, PHY_1000T_CTRL, phy_data);
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * igb_phy_init_script_5461s - Inits the BCM5461S PHY
|
||||
+ * @hw: pointer to the HW structure
|
||||
+ *
|
||||
+ * Initializes a Broadcom Gigabit PHY.
|
||||
+ **/
|
||||
+s32 igb_phy_init_script_5461s(struct e1000_hw *hw)
|
||||
+{
|
||||
+ u16 mii_reg_led = 0;
|
||||
+
|
||||
+ /* 1. Speed LED (Set the Link LED mode), Shadow 00010, 0x1C.bit2=1 */
|
||||
+ hw->phy.ops.write_reg(hw, 0x1C, 0x0800);
|
||||
+ hw->phy.ops.read_reg(hw, 0x1C, &mii_reg_led);
|
||||
+ mii_reg_led |= 0x0004;
|
||||
+ hw->phy.ops.write_reg(hw, 0x1C, mii_reg_led | 0x8000);
|
||||
+
|
||||
+ /* 2. Active LED (Set the Link LED mode), Shadow 01001, 0x1C.bit4=1, 0x10.bit5=0 */
|
||||
+ hw->phy.ops.write_reg(hw, 0x1C, 0x2400);
|
||||
+ hw->phy.ops.read_reg(hw, 0x1C, &mii_reg_led);
|
||||
+ mii_reg_led |= 0x0010;
|
||||
+ hw->phy.ops.write_reg(hw, 0x1C, mii_reg_led | 0x8000);
|
||||
+ hw->phy.ops.read_reg(hw, 0x10, &mii_reg_led);
|
||||
+ mii_reg_led &= 0xffdf;
|
||||
+ hw->phy.ops.write_reg(hw, 0x10, mii_reg_led);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * igb_get_phy_info_5461s - Retrieve 5461s PHY information
|
||||
+ * @hw: pointer to the HW structure
|
||||
+ *
|
||||
+ * Read PHY status to determine if link is up. If link is up, then
|
||||
+ * set/determine 10base-T extended distance and polarity correction. Read
|
||||
+ * PHY port status to determine MDI/MDIx and speed. Based on the speed,
|
||||
+ * determine on the cable length, local and remote receiver.
|
||||
+ **/
|
||||
+s32 igb_get_phy_info_5461s(struct e1000_hw *hw)
|
||||
+{
|
||||
+ struct e1000_phy_info *phy = &hw->phy;
|
||||
+ s32 ret_val;
|
||||
+ bool link;
|
||||
+
|
||||
+ ret_val = igb_phy_has_link(hw, 1, 0, &link);
|
||||
+ if (ret_val)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (!link) {
|
||||
+ ret_val = -E1000_ERR_CONFIG;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ phy->polarity_correction = true;
|
||||
+
|
||||
+ phy->is_mdix = true;
|
||||
+ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
|
||||
+ phy->local_rx = e1000_1000t_rx_status_ok;
|
||||
+ phy->remote_rx = e1000_1000t_rx_status_ok;
|
||||
+
|
||||
+out:
|
||||
+ return ret_val;
|
||||
+}
|
||||
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h
|
||||
index 9b622b3..3b28873 100644
|
||||
--- a/drivers/net/ethernet/intel/igb/e1000_phy.h
|
||||
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.h
|
||||
@@ -61,6 +61,8 @@ s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations,
|
||||
void igb_power_up_phy_copper(struct e1000_hw *hw);
|
||||
void igb_power_down_phy_copper(struct e1000_hw *hw);
|
||||
s32 igb_phy_init_script_igp3(struct e1000_hw *hw);
|
||||
+s32 igb_phy_init_script_5461s(struct e1000_hw *hw);
|
||||
+s32 igb_get_phy_info_5461s(struct e1000_hw *hw);
|
||||
s32 igb_initialize_M88E1512_phy(struct e1000_hw *hw);
|
||||
s32 igb_initialize_M88E1543_phy(struct e1000_hw *hw);
|
||||
s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
|
||||
index d1a44a8..1399989 100644
|
||||
--- a/drivers/net/ethernet/intel/igb/igb_main.c
|
||||
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
|
||||
@@ -7730,11 +7730,19 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
|
||||
data->phy_id = adapter->hw.phy.addr;
|
||||
break;
|
||||
case SIOCGMIIREG:
|
||||
+ adapter->hw.phy.addr = data->phy_id;
|
||||
if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
|
||||
&data->val_out))
|
||||
return -EIO;
|
||||
break;
|
||||
case SIOCSMIIREG:
|
||||
+ if (!capable(CAP_NET_ADMIN))
|
||||
+ return -EPERM;
|
||||
+ adapter->hw.phy.addr = data->phy_id;
|
||||
+ if (igb_write_phy_reg(&adapter->hw, data->reg_num & 0x1F,
|
||||
+ data->val_in))
|
||||
+ return -EIO;
|
||||
+ break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
diff -Naur a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
|
||||
--- a/drivers/net/ethernet/broadcom/tg3.c 2019-03-27 13:13:56.000000000 +0800
|
||||
+++ b/drivers/net/ethernet/broadcom/tg3.c 2019-04-26 11:08:20.307848693 +0800
|
||||
@@ -11734,6 +11734,12 @@
|
||||
pci_set_power_state(tp->pdev, PCI_D3hot);
|
||||
}
|
||||
|
||||
+ if (tg3_asic_rev(tp) == ASIC_REV_5720){
|
||||
+ /*Fixed ASIC_REV_5720 support 100M/10M feature */
|
||||
+ __tg3_writephy(tp, 0x8, 0x10, 0x1d0);
|
||||
+ __tg3_writephy(tp, 0x1f, 0x4, 0x5e1);
|
||||
+ }
|
||||
+
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
MAX6620 fix rpm calculation accuracy
|
||||
|
||||
From: Cumulus Networks <support@cumulusnetworks.com>
|
||||
|
||||
The driver only fills the most significant 8 bits of the fan tach
|
||||
count (11 bit value). Fixing the driver to use all of 11 bits for
|
||||
more accuracy.
|
||||
---
|
||||
drivers/hwmon/max6620.c | 105 +++++++++++++++++++++--------------------------
|
||||
1 file changed, 46 insertions(+), 59 deletions(-)
|
||||
|
||||
diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c
|
||||
index 3c337c7..76c1f7f 100644
|
||||
--- a/drivers/hwmon/max6620.c
|
||||
+++ b/drivers/hwmon/max6620.c
|
||||
@@ -46,6 +46,8 @@
|
||||
|
||||
/* clock: The clock frequency of the chip the driver should assume */
|
||||
static int clock = 8192;
|
||||
+static u32 sr = 2;
|
||||
+static u32 np = 2;
|
||||
|
||||
module_param(clock, int, S_IRUGO);
|
||||
|
||||
@@ -213,22 +215,22 @@ static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, cha
|
||||
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct max6620_data *data = max6620_update_device(dev);
|
||||
- int rpm;
|
||||
-
|
||||
- /*
|
||||
- * Calculation details:
|
||||
- *
|
||||
- * Each tachometer counts over an interval given by the "count"
|
||||
- * register (0.25, 0.5, 1 or 2 seconds). This module assumes
|
||||
- * that the fans produce two pulses per revolution (this seems
|
||||
- * to be the most common).
|
||||
- */
|
||||
- if(data->tach[attr->index] == 0 || data->tach[attr->index] == 255) {
|
||||
+ struct i2c_client *client = to_i2c_client(dev);
|
||||
+ u32 rpm = 0;
|
||||
+ u32 tach = 0;
|
||||
+ u32 tach1 = 0;
|
||||
+ u32 tach2 = 0;
|
||||
+
|
||||
+ tach1 = i2c_smbus_read_byte_data(client, tach_reg[attr->index]);
|
||||
+ tach1 = (tach1 << 3) & 0x7f8;
|
||||
+ tach2 = i2c_smbus_read_byte_data(client, tach_reg[attr->index] + 1);
|
||||
+ tach2 = (tach2 >> 5) & 0x7;
|
||||
+ tach = tach1 | tach2;
|
||||
+ if (tach == 0) {
|
||||
rpm = 0;
|
||||
} else {
|
||||
- rpm = ((clock / (data->tach[attr->index] << 3)) * 30 * DIV_FROM_REG(data->fandyn[attr->index]));
|
||||
+ rpm = (60 * sr * clock)/(tach * np);
|
||||
}
|
||||
-
|
||||
return sprintf(buf, "%d\n", rpm);
|
||||
}
|
||||
|
||||
@@ -236,22 +238,21 @@ static ssize_t get_target(struct device *dev, struct device_attribute *devattr,
|
||||
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct max6620_data *data = max6620_update_device(dev);
|
||||
- int kscale, ktach, rpm;
|
||||
-
|
||||
- /*
|
||||
- * Use the datasheet equation:
|
||||
- *
|
||||
- * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
|
||||
- *
|
||||
- * then multiply by 60 to give rpm.
|
||||
- */
|
||||
-
|
||||
- kscale = DIV_FROM_REG(data->fandyn[attr->index]);
|
||||
- ktach = data->target[attr->index];
|
||||
- if(ktach == 0) {
|
||||
+ struct i2c_client *client = to_i2c_client(dev);
|
||||
+ u32 rpm;
|
||||
+ u32 target;
|
||||
+ u32 target1;
|
||||
+ u32 target2;
|
||||
+
|
||||
+ target1 = i2c_smbus_read_byte_data(client, target_reg[attr->index]);
|
||||
+ target1 = (target1 << 3) & 0x7f8;
|
||||
+ target2 = i2c_smbus_read_byte_data(client, target_reg[attr->index] + 1);
|
||||
+ target2 = (target2 >> 5) & 0x7;
|
||||
+ target = target1 | target2;
|
||||
+ if (target == 0) {
|
||||
rpm = 0;
|
||||
} else {
|
||||
- rpm = ((60 * kscale * clock) / (ktach << 3));
|
||||
+ rpm = (60 * sr * clock)/(target * np);
|
||||
}
|
||||
return sprintf(buf, "%d\n", rpm);
|
||||
}
|
||||
@@ -261,9 +262,11 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct max6620_data *data = i2c_get_clientdata(client);
|
||||
- int kscale, ktach;
|
||||
- unsigned long rpm;
|
||||
+ u32 rpm;
|
||||
int err;
|
||||
+ u32 target;
|
||||
+ u32 target1;
|
||||
+ u32 target2;
|
||||
|
||||
err = kstrtoul(buf, 10, &rpm);
|
||||
if (err)
|
||||
@@ -271,25 +274,13 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
|
||||
|
||||
rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
|
||||
|
||||
- /*
|
||||
- * Divide the required speed by 60 to get from rpm to rps, then
|
||||
- * use the datasheet equation:
|
||||
- *
|
||||
- * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1
|
||||
- */
|
||||
-
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
- kscale = DIV_FROM_REG(data->fandyn[attr->index]);
|
||||
- ktach = ((60 * kscale * clock) / rpm);
|
||||
- if (ktach < 0)
|
||||
- ktach = 0;
|
||||
- if (ktach > 255)
|
||||
- ktach = 255;
|
||||
- data->target[attr->index] = ktach;
|
||||
-
|
||||
- i2c_smbus_write_byte_data(client, target_reg[attr->index], data->target[attr->index]);
|
||||
- i2c_smbus_write_byte_data(client, target_reg[attr->index]+0x01, 0x00);
|
||||
+ target = (60 * sr * 8192)/(rpm * np);
|
||||
+ target1 = (target >> 3) & 0xff;
|
||||
+ target2 = (target << 5) & 0xe0;
|
||||
+ i2c_smbus_write_byte_data(client, target_reg[attr->index], target1);
|
||||
+ i2c_smbus_write_byte_data(client, target_reg[attr->index] + 1, target2);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
@@ -609,8 +600,11 @@ static int max6620_init_client(struct i2c_client *client) {
|
||||
}
|
||||
|
||||
|
||||
-
|
||||
- if (i2c_smbus_write_byte_data(client, MAX6620_REG_CONFIG, config)) {
|
||||
+ /*
|
||||
+ * Set bit 4, disable other fans from going full speed on a fail
|
||||
+ * failure.
|
||||
+ */
|
||||
+ if (i2c_smbus_write_byte_data(client, MAX6620_REG_CONFIG, config | 0x10)) {
|
||||
dev_err(&client->dev, "Config write error, aborting.\n");
|
||||
return err;
|
||||
}
|
||||
@@ -618,28 +612,21 @@ static int max6620_init_client(struct i2c_client *client) {
|
||||
data->config = config;
|
||||
for (i = 0; i < 4; i++) {
|
||||
data->fancfg[i] = i2c_smbus_read_byte_data(client, config_reg[i]);
|
||||
- data->fancfg[i] |= 0x80; // enable TACH monitoring
|
||||
+ data->fancfg[i] |= 0xa8; // enable TACH monitoring
|
||||
i2c_smbus_write_byte_data(client, config_reg[i], data->fancfg[i]);
|
||||
data->fandyn[i] = i2c_smbus_read_byte_data(client, dyn_reg[i]);
|
||||
- data-> fandyn[i] |= 0x1C;
|
||||
+ /* 2 counts (001) and Rate change 100 (0.125 secs) */
|
||||
+ data-> fandyn[i] = 0x30;
|
||||
i2c_smbus_write_byte_data(client, dyn_reg[i], data->fandyn[i]);
|
||||
data->tach[i] = i2c_smbus_read_byte_data(client, tach_reg[i]);
|
||||
data->volt[i] = i2c_smbus_read_byte_data(client, volt_reg[i]);
|
||||
data->target[i] = i2c_smbus_read_byte_data(client, target_reg[i]);
|
||||
data->dac[i] = i2c_smbus_read_byte_data(client, dac_reg[i]);
|
||||
|
||||
-
|
||||
-
|
||||
}
|
||||
-
|
||||
-
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
static struct max6620_data *max6620_update_device(struct device *dev)
|
||||
{
|
||||
int i;
|
||||
@@ -678,7 +665,7 @@ static struct max6620_data *max6620_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
-module_i2c_driver(max6620_driver);
|
||||
+// module_i2c_driver(max6620_driver);
|
||||
|
||||
static int __init max6620_init(void)
|
||||
{
|
||||
@@ -0,0 +1,113 @@
|
||||
Update MAX6620 driver to support newer kernel version
|
||||
|
||||
From: Shuotian Cheng <shuche@microsoft.com>
|
||||
|
||||
|
||||
---
|
||||
drivers/hwmon/max6620.c | 25 +++++++++++--------------
|
||||
1 file changed, 11 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c
|
||||
index 76c1f7f..fb49195 100644
|
||||
--- a/drivers/hwmon/max6620.c
|
||||
+++ b/drivers/hwmon/max6620.c
|
||||
@@ -183,7 +183,7 @@ static struct i2c_driver max6620_driver = {
|
||||
.name = "max6620",
|
||||
},
|
||||
.probe = max6620_probe,
|
||||
- .remove = __devexit_p(max6620_remove),
|
||||
+ .remove = max6620_remove,
|
||||
.id_table = max6620_id,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
@@ -231,6 +231,7 @@ static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, cha
|
||||
} else {
|
||||
rpm = (60 * sr * clock)/(tach * np);
|
||||
}
|
||||
+
|
||||
return sprintf(buf, "%d\n", rpm);
|
||||
}
|
||||
|
||||
@@ -262,17 +263,17 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
struct max6620_data *data = i2c_get_clientdata(client);
|
||||
- u32 rpm;
|
||||
+ unsigned long rpm;
|
||||
int err;
|
||||
- u32 target;
|
||||
- u32 target1;
|
||||
- u32 target2;
|
||||
+ unsigned long target;
|
||||
+ unsigned long target1;
|
||||
+ unsigned long target2;
|
||||
|
||||
err = kstrtoul(buf, 10, &rpm);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
- rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
|
||||
+ rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@@ -326,7 +327,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, con
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
- pwm = SENSORS_LIMIT(pwm, 0, 255);
|
||||
+ pwm = clamp_val(pwm, 0, 255);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@@ -534,7 +535,7 @@ static struct attribute_group max6620_attr_grp = {
|
||||
* Real code
|
||||
*/
|
||||
|
||||
-static int __devinit max6620_probe(struct i2c_client *client, const struct i2c_device_id *id) {
|
||||
+static int max6620_probe(struct i2c_client *client, const struct i2c_device_id *id) {
|
||||
|
||||
struct max6620_data *data;
|
||||
int err;
|
||||
@@ -575,7 +576,7 @@ dev_info(&client->dev, "Sysfs entries created\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
-static int __devexit max6620_remove(struct i2c_client *client) {
|
||||
+static int max6620_remove(struct i2c_client *client) {
|
||||
|
||||
struct max6620_data *data = i2c_get_clientdata(client);
|
||||
|
||||
@@ -599,7 +600,6 @@ static int max6620_init_client(struct i2c_client *client) {
|
||||
return err;
|
||||
}
|
||||
|
||||
-
|
||||
/*
|
||||
* Set bit 4, disable other fans from going full speed on a fail
|
||||
* failure.
|
||||
@@ -615,14 +615,13 @@ static int max6620_init_client(struct i2c_client *client) {
|
||||
data->fancfg[i] |= 0xa8; // enable TACH monitoring
|
||||
i2c_smbus_write_byte_data(client, config_reg[i], data->fancfg[i]);
|
||||
data->fandyn[i] = i2c_smbus_read_byte_data(client, dyn_reg[i]);
|
||||
- /* 2 counts (001) and Rate change 100 (0.125 secs) */
|
||||
+ /* 2 counts (001) and Rate change 100 (0.125 secs) */
|
||||
data-> fandyn[i] = 0x30;
|
||||
i2c_smbus_write_byte_data(client, dyn_reg[i], data->fandyn[i]);
|
||||
data->tach[i] = i2c_smbus_read_byte_data(client, tach_reg[i]);
|
||||
data->volt[i] = i2c_smbus_read_byte_data(client, volt_reg[i]);
|
||||
data->target[i] = i2c_smbus_read_byte_data(client, target_reg[i]);
|
||||
data->dac[i] = i2c_smbus_read_byte_data(client, dac_reg[i]);
|
||||
-
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -665,8 +664,6 @@ static struct max6620_data *max6620_update_device(struct device *dev)
|
||||
return data;
|
||||
}
|
||||
|
||||
-// module_i2c_driver(max6620_driver);
|
||||
-
|
||||
static int __init max6620_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max6620_driver);
|
||||
@@ -0,0 +1,753 @@
|
||||
Driver for MAX6620 Fan sensor
|
||||
|
||||
From: Cumulus Networks <support@cumulusnetworks.com>
|
||||
|
||||
|
||||
---
|
||||
drivers/hwmon/Kconfig | 10 +
|
||||
drivers/hwmon/Makefile | 1
|
||||
drivers/hwmon/max6620.c | 702 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 713 insertions(+)
|
||||
create mode 100644 drivers/hwmon/max6620.c
|
||||
|
||||
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
|
||||
index 02d3d85..ca38e05 100644
|
||||
--- a/drivers/hwmon/Kconfig
|
||||
+++ b/drivers/hwmon/Kconfig
|
||||
@@ -784,6 +784,16 @@ config SENSORS_MAX6650
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called max6650.
|
||||
|
||||
+config SENSORS_MAX6620
|
||||
+ tristate "Maxim MAX6620 sensor chip"
|
||||
+ depends on I2C
|
||||
+ help
|
||||
+ If you say yes here you get support for the MAX6620
|
||||
+ sensor chips.
|
||||
+
|
||||
+ This driver can also be built as a module. If so, the module
|
||||
+ will be called max6620.
|
||||
+
|
||||
config SENSORS_MAX6697
|
||||
tristate "Maxim MAX6697 and compatibles"
|
||||
depends on I2C
|
||||
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
|
||||
index 3dc0f02..8837a7b 100644
|
||||
--- a/drivers/hwmon/Makefile
|
||||
+++ b/drivers/hwmon/Makefile
|
||||
@@ -111,6 +111,7 @@ obj-$(CONFIG_SENSORS_MAX197) += max197.o
|
||||
obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
|
||||
obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
|
||||
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
|
||||
+obj-$(CONFIG_SENSORS_MAX6620) += max6620.o
|
||||
obj-$(CONFIG_SENSORS_MAX6697) += max6697.o
|
||||
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
|
||||
obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
|
||||
diff --git a/drivers/hwmon/max6620.c b/drivers/hwmon/max6620.c
|
||||
new file mode 100644
|
||||
index 0000000..3c337c7
|
||||
--- /dev/null
|
||||
+++ b/drivers/hwmon/max6620.c
|
||||
@@ -0,0 +1,702 @@
|
||||
+/*
|
||||
+ * max6620.c - Linux Kernel module for hardware monitoring.
|
||||
+ *
|
||||
+ * (C) 2012 by L. Grunenberg <contact@lgrunenberg.de>
|
||||
+ *
|
||||
+ * based on code written by :
|
||||
+ * 2007 by Hans J. Koch <hjk@hansjkoch.de>
|
||||
+ * John Morris <john.morris@spirentcom.com>
|
||||
+ * Copyright (c) 2003 Spirent Communications
|
||||
+ * and Claus Gindhart <claus.gindhart@kontron.com>
|
||||
+ *
|
||||
+ * This module has only been tested with the MAX6620 chip.
|
||||
+ *
|
||||
+ * The datasheet was last seen at:
|
||||
+ *
|
||||
+ * http://pdfserv.maxim-ic.com/en/ds/MAX6620.pdf
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ *
|
||||
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/jiffies.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/hwmon.h>
|
||||
+#include <linux/hwmon-sysfs.h>
|
||||
+#include <linux/err.h>
|
||||
+
|
||||
+/*
|
||||
+ * Insmod parameters
|
||||
+ */
|
||||
+
|
||||
+
|
||||
+/* clock: The clock frequency of the chip the driver should assume */
|
||||
+static int clock = 8192;
|
||||
+
|
||||
+module_param(clock, int, S_IRUGO);
|
||||
+
|
||||
+static const unsigned short normal_i2c[] = {0x0a, 0x1a, 0x2a, I2C_CLIENT_END};
|
||||
+
|
||||
+/*
|
||||
+ * MAX 6620 registers
|
||||
+ */
|
||||
+
|
||||
+#define MAX6620_REG_CONFIG 0x00
|
||||
+#define MAX6620_REG_FAULT 0x01
|
||||
+#define MAX6620_REG_CONF_FAN0 0x02
|
||||
+#define MAX6620_REG_CONF_FAN1 0x03
|
||||
+#define MAX6620_REG_CONF_FAN2 0x04
|
||||
+#define MAX6620_REG_CONF_FAN3 0x05
|
||||
+#define MAX6620_REG_DYN_FAN0 0x06
|
||||
+#define MAX6620_REG_DYN_FAN1 0x07
|
||||
+#define MAX6620_REG_DYN_FAN2 0x08
|
||||
+#define MAX6620_REG_DYN_FAN3 0x09
|
||||
+#define MAX6620_REG_TACH0 0x10
|
||||
+#define MAX6620_REG_TACH1 0x12
|
||||
+#define MAX6620_REG_TACH2 0x14
|
||||
+#define MAX6620_REG_TACH3 0x16
|
||||
+#define MAX6620_REG_VOLT0 0x18
|
||||
+#define MAX6620_REG_VOLT1 0x1A
|
||||
+#define MAX6620_REG_VOLT2 0x1C
|
||||
+#define MAX6620_REG_VOLT3 0x1E
|
||||
+#define MAX6620_REG_TAR0 0x20
|
||||
+#define MAX6620_REG_TAR1 0x22
|
||||
+#define MAX6620_REG_TAR2 0x24
|
||||
+#define MAX6620_REG_TAR3 0x26
|
||||
+#define MAX6620_REG_DAC0 0x28
|
||||
+#define MAX6620_REG_DAC1 0x2A
|
||||
+#define MAX6620_REG_DAC2 0x2C
|
||||
+#define MAX6620_REG_DAC3 0x2E
|
||||
+
|
||||
+/*
|
||||
+ * Config register bits
|
||||
+ */
|
||||
+
|
||||
+#define MAX6620_CFG_RUN 0x80
|
||||
+#define MAX6620_CFG_POR 0x40
|
||||
+#define MAX6620_CFG_TIMEOUT 0x20
|
||||
+#define MAX6620_CFG_FULLFAN 0x10
|
||||
+#define MAX6620_CFG_OSC 0x08
|
||||
+#define MAX6620_CFG_WD_MASK 0x06
|
||||
+#define MAX6620_CFG_WD_2 0x02
|
||||
+#define MAX6620_CFG_WD_6 0x04
|
||||
+#define MAX6620_CFG_WD10 0x06
|
||||
+#define MAX6620_CFG_WD 0x01
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Failure status register bits
|
||||
+ */
|
||||
+
|
||||
+#define MAX6620_FAIL_TACH0 0x10
|
||||
+#define MAX6620_FAIL_TACH1 0x20
|
||||
+#define MAX6620_FAIL_TACH2 0x40
|
||||
+#define MAX6620_FAIL_TACH3 0x80
|
||||
+#define MAX6620_FAIL_MASK0 0x01
|
||||
+#define MAX6620_FAIL_MASK1 0x02
|
||||
+#define MAX6620_FAIL_MASK2 0x04
|
||||
+#define MAX6620_FAIL_MASK3 0x08
|
||||
+
|
||||
+
|
||||
+/* Minimum and maximum values of the FAN-RPM */
|
||||
+#define FAN_RPM_MIN 240
|
||||
+#define FAN_RPM_MAX 30000
|
||||
+
|
||||
+#define DIV_FROM_REG(reg) (1 << ((reg & 0xE0) >> 5))
|
||||
+
|
||||
+static int max6620_probe(struct i2c_client *client, const struct i2c_device_id *id);
|
||||
+static int max6620_init_client(struct i2c_client *client);
|
||||
+static int max6620_remove(struct i2c_client *client);
|
||||
+static struct max6620_data *max6620_update_device(struct device *dev);
|
||||
+
|
||||
+static const u8 config_reg[] = {
|
||||
+ MAX6620_REG_CONF_FAN0,
|
||||
+ MAX6620_REG_CONF_FAN1,
|
||||
+ MAX6620_REG_CONF_FAN2,
|
||||
+ MAX6620_REG_CONF_FAN3,
|
||||
+};
|
||||
+
|
||||
+static const u8 dyn_reg[] = {
|
||||
+ MAX6620_REG_DYN_FAN0,
|
||||
+ MAX6620_REG_DYN_FAN1,
|
||||
+ MAX6620_REG_DYN_FAN2,
|
||||
+ MAX6620_REG_DYN_FAN3,
|
||||
+};
|
||||
+
|
||||
+static const u8 tach_reg[] = {
|
||||
+ MAX6620_REG_TACH0,
|
||||
+ MAX6620_REG_TACH1,
|
||||
+ MAX6620_REG_TACH2,
|
||||
+ MAX6620_REG_TACH3,
|
||||
+};
|
||||
+
|
||||
+static const u8 volt_reg[] = {
|
||||
+ MAX6620_REG_VOLT0,
|
||||
+ MAX6620_REG_VOLT1,
|
||||
+ MAX6620_REG_VOLT2,
|
||||
+ MAX6620_REG_VOLT3,
|
||||
+};
|
||||
+
|
||||
+static const u8 target_reg[] = {
|
||||
+ MAX6620_REG_TAR0,
|
||||
+ MAX6620_REG_TAR1,
|
||||
+ MAX6620_REG_TAR2,
|
||||
+ MAX6620_REG_TAR3,
|
||||
+};
|
||||
+
|
||||
+static const u8 dac_reg[] = {
|
||||
+ MAX6620_REG_DAC0,
|
||||
+ MAX6620_REG_DAC1,
|
||||
+ MAX6620_REG_DAC2,
|
||||
+ MAX6620_REG_DAC3,
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Driver data (common to all clients)
|
||||
+ */
|
||||
+
|
||||
+static const struct i2c_device_id max6620_id[] = {
|
||||
+ { "max6620", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, max6620_id);
|
||||
+
|
||||
+static struct i2c_driver max6620_driver = {
|
||||
+ .class = I2C_CLASS_HWMON,
|
||||
+ .driver = {
|
||||
+ .name = "max6620",
|
||||
+ },
|
||||
+ .probe = max6620_probe,
|
||||
+ .remove = __devexit_p(max6620_remove),
|
||||
+ .id_table = max6620_id,
|
||||
+ .address_list = normal_i2c,
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Client data (each client gets its own)
|
||||
+ */
|
||||
+
|
||||
+struct max6620_data {
|
||||
+ struct device *hwmon_dev;
|
||||
+ struct mutex update_lock;
|
||||
+ int nr_fans;
|
||||
+ char valid; /* zero until following fields are valid */
|
||||
+ unsigned long last_updated; /* in jiffies */
|
||||
+
|
||||
+ /* register values */
|
||||
+ u8 speed[4];
|
||||
+ u8 config;
|
||||
+ u8 fancfg[4];
|
||||
+ u8 fandyn[4];
|
||||
+ u8 tach[4];
|
||||
+ u8 volt[4];
|
||||
+ u8 target[4];
|
||||
+ u8 dac[4];
|
||||
+ u8 fault;
|
||||
+};
|
||||
+
|
||||
+static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, char *buf) {
|
||||
+
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ struct max6620_data *data = max6620_update_device(dev);
|
||||
+ int rpm;
|
||||
+
|
||||
+ /*
|
||||
+ * Calculation details:
|
||||
+ *
|
||||
+ * Each tachometer counts over an interval given by the "count"
|
||||
+ * register (0.25, 0.5, 1 or 2 seconds). This module assumes
|
||||
+ * that the fans produce two pulses per revolution (this seems
|
||||
+ * to be the most common).
|
||||
+ */
|
||||
+ if(data->tach[attr->index] == 0 || data->tach[attr->index] == 255) {
|
||||
+ rpm = 0;
|
||||
+ } else {
|
||||
+ rpm = ((clock / (data->tach[attr->index] << 3)) * 30 * DIV_FROM_REG(data->fandyn[attr->index]));
|
||||
+ }
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", rpm);
|
||||
+}
|
||||
+
|
||||
+static ssize_t get_target(struct device *dev, struct device_attribute *devattr, char *buf) {
|
||||
+
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ struct max6620_data *data = max6620_update_device(dev);
|
||||
+ int kscale, ktach, rpm;
|
||||
+
|
||||
+ /*
|
||||
+ * Use the datasheet equation:
|
||||
+ *
|
||||
+ * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
|
||||
+ *
|
||||
+ * then multiply by 60 to give rpm.
|
||||
+ */
|
||||
+
|
||||
+ kscale = DIV_FROM_REG(data->fandyn[attr->index]);
|
||||
+ ktach = data->target[attr->index];
|
||||
+ if(ktach == 0) {
|
||||
+ rpm = 0;
|
||||
+ } else {
|
||||
+ rpm = ((60 * kscale * clock) / (ktach << 3));
|
||||
+ }
|
||||
+ return sprintf(buf, "%d\n", rpm);
|
||||
+}
|
||||
+
|
||||
+static ssize_t set_target(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) {
|
||||
+
|
||||
+ struct i2c_client *client = to_i2c_client(dev);
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ struct max6620_data *data = i2c_get_clientdata(client);
|
||||
+ int kscale, ktach;
|
||||
+ unsigned long rpm;
|
||||
+ int err;
|
||||
+
|
||||
+ err = kstrtoul(buf, 10, &rpm);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
|
||||
+
|
||||
+ /*
|
||||
+ * Divide the required speed by 60 to get from rpm to rps, then
|
||||
+ * use the datasheet equation:
|
||||
+ *
|
||||
+ * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1
|
||||
+ */
|
||||
+
|
||||
+ mutex_lock(&data->update_lock);
|
||||
+
|
||||
+ kscale = DIV_FROM_REG(data->fandyn[attr->index]);
|
||||
+ ktach = ((60 * kscale * clock) / rpm);
|
||||
+ if (ktach < 0)
|
||||
+ ktach = 0;
|
||||
+ if (ktach > 255)
|
||||
+ ktach = 255;
|
||||
+ data->target[attr->index] = ktach;
|
||||
+
|
||||
+ i2c_smbus_write_byte_data(client, target_reg[attr->index], data->target[attr->index]);
|
||||
+ i2c_smbus_write_byte_data(client, target_reg[attr->index]+0x01, 0x00);
|
||||
+
|
||||
+ mutex_unlock(&data->update_lock);
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Get/set the fan speed in open loop mode using pwm1 sysfs file.
|
||||
+ * Speed is given as a relative value from 0 to 255, where 255 is maximum
|
||||
+ * speed. Note that this is done by writing directly to the chip's DAC,
|
||||
+ * it won't change the closed loop speed set by fan1_target.
|
||||
+ * Also note that due to rounding errors it is possible that you don't read
|
||||
+ * back exactly the value you have set.
|
||||
+ */
|
||||
+
|
||||
+static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr, char *buf) {
|
||||
+
|
||||
+ int pwm;
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ struct max6620_data *data = max6620_update_device(dev);
|
||||
+
|
||||
+ /*
|
||||
+ * Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
|
||||
+ * Lower DAC values mean higher speeds.
|
||||
+ */
|
||||
+ pwm = ((int)data->volt[attr->index]);
|
||||
+
|
||||
+ if (pwm < 0)
|
||||
+ pwm = 0;
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", pwm);
|
||||
+}
|
||||
+
|
||||
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) {
|
||||
+
|
||||
+ struct i2c_client *client = to_i2c_client(dev);
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ struct max6620_data *data = i2c_get_clientdata(client);
|
||||
+ unsigned long pwm;
|
||||
+ int err;
|
||||
+
|
||||
+ err = kstrtoul(buf, 10, &pwm);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ pwm = SENSORS_LIMIT(pwm, 0, 255);
|
||||
+
|
||||
+ mutex_lock(&data->update_lock);
|
||||
+
|
||||
+ data->dac[attr->index] = pwm;
|
||||
+
|
||||
+
|
||||
+ i2c_smbus_write_byte_data(client, dac_reg[attr->index], data->dac[attr->index]);
|
||||
+ i2c_smbus_write_byte_data(client, dac_reg[attr->index]+1, 0x00);
|
||||
+
|
||||
+ mutex_unlock(&data->update_lock);
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Get/Set controller mode:
|
||||
+ * Possible values:
|
||||
+ * 0 = Fan always on
|
||||
+ * 1 = Open loop, Voltage is set according to speed, not regulated.
|
||||
+ * 2 = Closed loop, RPM for all fans regulated by fan1 tachometer
|
||||
+ */
|
||||
+
|
||||
+static ssize_t get_enable(struct device *dev, struct device_attribute *devattr, char *buf) {
|
||||
+
|
||||
+ struct max6620_data *data = max6620_update_device(dev);
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ int mode = (data->fancfg[attr->index] & 0x80 ) >> 7;
|
||||
+ int sysfs_modes[2] = {1, 2};
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", sysfs_modes[mode]);
|
||||
+}
|
||||
+
|
||||
+static ssize_t set_enable(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) {
|
||||
+
|
||||
+ struct i2c_client *client = to_i2c_client(dev);
|
||||
+ struct max6620_data *data = i2c_get_clientdata(client);
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ int max6620_modes[3] = {0, 1, 0};
|
||||
+ unsigned long mode;
|
||||
+ int err;
|
||||
+
|
||||
+ err = kstrtoul(buf, 10, &mode);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (mode > 2)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mutex_lock(&data->update_lock);
|
||||
+
|
||||
+ data->fancfg[attr->index] = i2c_smbus_read_byte_data(client, config_reg[attr->index]);
|
||||
+ data->fancfg[attr->index] = (data->fancfg[attr->index] & ~0x80)
|
||||
+ | (max6620_modes[mode] << 7);
|
||||
+
|
||||
+ i2c_smbus_write_byte_data(client, config_reg[attr->index], data->fancfg[attr->index]);
|
||||
+
|
||||
+ mutex_unlock(&data->update_lock);
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Read/write functions for fan1_div sysfs file. The MAX6620 has no such
|
||||
+ * divider. We handle this by converting between divider and counttime:
|
||||
+ *
|
||||
+ * (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, 3, 4 or 5
|
||||
+ *
|
||||
+ * Lower values of k allow to connect a faster fan without the risk of
|
||||
+ * counter overflow. The price is lower resolution. You can also set counttime
|
||||
+ * using the module parameter. Note that the module parameter "prescaler" also
|
||||
+ * influences the behaviour. Unfortunately, there's no sysfs attribute
|
||||
+ * defined for that. See the data sheet for details.
|
||||
+ */
|
||||
+
|
||||
+static ssize_t get_div(struct device *dev, struct device_attribute *devattr, char *buf) {
|
||||
+
|
||||
+ struct max6620_data *data = max6620_update_device(dev);
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", DIV_FROM_REG(data->fandyn[attr->index]));
|
||||
+}
|
||||
+
|
||||
+static ssize_t set_div(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) {
|
||||
+
|
||||
+ struct i2c_client *client = to_i2c_client(dev);
|
||||
+ struct max6620_data *data = i2c_get_clientdata(client);
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ unsigned long div;
|
||||
+ int err;
|
||||
+ u8 div_bin;
|
||||
+
|
||||
+ err = kstrtoul(buf, 10, &div);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ mutex_lock(&data->update_lock);
|
||||
+ switch (div) {
|
||||
+ case 1:
|
||||
+ div_bin = 0;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ div_bin = 1;
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ div_bin = 2;
|
||||
+ break;
|
||||
+ case 8:
|
||||
+ div_bin = 3;
|
||||
+ break;
|
||||
+ case 16:
|
||||
+ div_bin = 4;
|
||||
+ break;
|
||||
+ case 32:
|
||||
+ div_bin = 5;
|
||||
+ break;
|
||||
+ default:
|
||||
+ mutex_unlock(&data->update_lock);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ data->fandyn[attr->index] &= 0x1F;
|
||||
+ data->fandyn[attr->index] |= div_bin << 5;
|
||||
+ i2c_smbus_write_byte_data(client, dyn_reg[attr->index], data->fandyn[attr->index]);
|
||||
+ mutex_unlock(&data->update_lock);
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Get alarm stati:
|
||||
+ * Possible values:
|
||||
+ * 0 = no alarm
|
||||
+ * 1 = alarm
|
||||
+ */
|
||||
+
|
||||
+static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr, char *buf) {
|
||||
+
|
||||
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||
+ struct max6620_data *data = max6620_update_device(dev);
|
||||
+ struct i2c_client *client = to_i2c_client(dev);
|
||||
+ int alarm = 0;
|
||||
+
|
||||
+ if (data->fault & (1 << attr->index)) {
|
||||
+ mutex_lock(&data->update_lock);
|
||||
+ alarm = 1;
|
||||
+ data->fault &= ~(1 << attr->index);
|
||||
+ data->fault |= i2c_smbus_read_byte_data(client,
|
||||
+ MAX6620_REG_FAULT);
|
||||
+ mutex_unlock(&data->update_lock);
|
||||
+ }
|
||||
+
|
||||
+ return sprintf(buf, "%d\n", alarm);
|
||||
+}
|
||||
+
|
||||
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);
|
||||
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);
|
||||
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2);
|
||||
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3);
|
||||
+static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target, 0);
|
||||
+static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div, 0);
|
||||
+// static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable, 0);
|
||||
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 0);
|
||||
+static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO, get_target, set_target, 1);
|
||||
+static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, get_div, set_div, 1);
|
||||
+// static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, get_enable, set_enable, 1);
|
||||
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 1);
|
||||
+static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO, get_target, set_target, 2);
|
||||
+static SENSOR_DEVICE_ATTR(fan3_div, S_IWUSR | S_IRUGO, get_div, set_div, 2);
|
||||
+// static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, get_enable, set_enable, 2);
|
||||
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 2);
|
||||
+static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO, get_target, set_target, 3);
|
||||
+static SENSOR_DEVICE_ATTR(fan4_div, S_IWUSR | S_IRUGO, get_div, set_div, 3);
|
||||
+// static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, get_enable, set_enable, 3);
|
||||
+static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 3);
|
||||
+
|
||||
+static struct attribute *max6620_attrs[] = {
|
||||
+ &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_fan1_target.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
|
||||
+// &sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
||||
+ &sensor_dev_attr_pwm1.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan2_target.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
|
||||
+// &sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
||||
+ &sensor_dev_attr_pwm2.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan3_target.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan3_div.dev_attr.attr,
|
||||
+// &sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
||||
+ &sensor_dev_attr_pwm3.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan4_target.dev_attr.attr,
|
||||
+ &sensor_dev_attr_fan4_div.dev_attr.attr,
|
||||
+// &sensor_dev_attr_pwm4_enable.dev_attr.attr,
|
||||
+ &sensor_dev_attr_pwm4.dev_attr.attr,
|
||||
+ NULL
|
||||
+};
|
||||
+
|
||||
+static struct attribute_group max6620_attr_grp = {
|
||||
+ .attrs = max6620_attrs,
|
||||
+};
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Real code
|
||||
+ */
|
||||
+
|
||||
+static int __devinit max6620_probe(struct i2c_client *client, const struct i2c_device_id *id) {
|
||||
+
|
||||
+ struct max6620_data *data;
|
||||
+ int err;
|
||||
+
|
||||
+ data = devm_kzalloc(&client->dev, sizeof(struct max6620_data), GFP_KERNEL);
|
||||
+ if (!data) {
|
||||
+ dev_err(&client->dev, "out of memory.\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ i2c_set_clientdata(client, data);
|
||||
+ mutex_init(&data->update_lock);
|
||||
+ data->nr_fans = id->driver_data;
|
||||
+
|
||||
+ /*
|
||||
+ * Initialize the max6620 chip
|
||||
+ */
|
||||
+ dev_info(&client->dev, "About to initialize module\n");
|
||||
+
|
||||
+ err = max6620_init_client(client);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ dev_info(&client->dev, "Module initialized\n");
|
||||
+
|
||||
+ err = sysfs_create_group(&client->dev.kobj, &max6620_attr_grp);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+dev_info(&client->dev, "Sysfs entries created\n");
|
||||
+
|
||||
+ data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
+ if (!IS_ERR(data->hwmon_dev))
|
||||
+ return 0;
|
||||
+
|
||||
+ err = PTR_ERR(data->hwmon_dev);
|
||||
+ dev_err(&client->dev, "error registering hwmon device.\n");
|
||||
+
|
||||
+ sysfs_remove_group(&client->dev.kobj, &max6620_attr_grp);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int __devexit max6620_remove(struct i2c_client *client) {
|
||||
+
|
||||
+ struct max6620_data *data = i2c_get_clientdata(client);
|
||||
+
|
||||
+ hwmon_device_unregister(data->hwmon_dev);
|
||||
+
|
||||
+ sysfs_remove_group(&client->dev.kobj, &max6620_attr_grp);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int max6620_init_client(struct i2c_client *client) {
|
||||
+
|
||||
+ struct max6620_data *data = i2c_get_clientdata(client);
|
||||
+ int config;
|
||||
+ int err = -EIO;
|
||||
+ int i;
|
||||
+
|
||||
+ config = i2c_smbus_read_byte_data(client, MAX6620_REG_CONFIG);
|
||||
+
|
||||
+ if (config < 0) {
|
||||
+ dev_err(&client->dev, "Error reading config, aborting.\n");
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+
|
||||
+ if (i2c_smbus_write_byte_data(client, MAX6620_REG_CONFIG, config)) {
|
||||
+ dev_err(&client->dev, "Config write error, aborting.\n");
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ data->config = config;
|
||||
+ for (i = 0; i < 4; i++) {
|
||||
+ data->fancfg[i] = i2c_smbus_read_byte_data(client, config_reg[i]);
|
||||
+ data->fancfg[i] |= 0x80; // enable TACH monitoring
|
||||
+ i2c_smbus_write_byte_data(client, config_reg[i], data->fancfg[i]);
|
||||
+ data->fandyn[i] = i2c_smbus_read_byte_data(client, dyn_reg[i]);
|
||||
+ data-> fandyn[i] |= 0x1C;
|
||||
+ i2c_smbus_write_byte_data(client, dyn_reg[i], data->fandyn[i]);
|
||||
+ data->tach[i] = i2c_smbus_read_byte_data(client, tach_reg[i]);
|
||||
+ data->volt[i] = i2c_smbus_read_byte_data(client, volt_reg[i]);
|
||||
+ data->target[i] = i2c_smbus_read_byte_data(client, target_reg[i]);
|
||||
+ data->dac[i] = i2c_smbus_read_byte_data(client, dac_reg[i]);
|
||||
+
|
||||
+
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+static struct max6620_data *max6620_update_device(struct device *dev)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct i2c_client *client = to_i2c_client(dev);
|
||||
+ struct max6620_data *data = i2c_get_clientdata(client);
|
||||
+
|
||||
+ mutex_lock(&data->update_lock);
|
||||
+
|
||||
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
|
||||
+
|
||||
+ for (i = 0; i < 4; i++) {
|
||||
+ data->fancfg[i] = i2c_smbus_read_byte_data(client, config_reg[i]);
|
||||
+ data->fandyn[i] = i2c_smbus_read_byte_data(client, dyn_reg[i]);
|
||||
+ data->tach[i] = i2c_smbus_read_byte_data(client, tach_reg[i]);
|
||||
+ data->volt[i] = i2c_smbus_read_byte_data(client, volt_reg[i]);
|
||||
+ data->target[i] = i2c_smbus_read_byte_data(client, target_reg[i]);
|
||||
+ data->dac[i] = i2c_smbus_read_byte_data(client, dac_reg[i]);
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ /*
|
||||
+ * Alarms are cleared on read in case the condition that
|
||||
+ * caused the alarm is removed. Keep the value latched here
|
||||
+ * for providing the register through different alarm files.
|
||||
+ */
|
||||
+ u8 fault_reg;
|
||||
+ fault_reg = i2c_smbus_read_byte_data(client, MAX6620_REG_FAULT);
|
||||
+ data->fault |= (fault_reg >> 4) & (fault_reg & 0x0F);
|
||||
+
|
||||
+ data->last_updated = jiffies;
|
||||
+ data->valid = 1;
|
||||
+ }
|
||||
+
|
||||
+ mutex_unlock(&data->update_lock);
|
||||
+
|
||||
+ return data;
|
||||
+}
|
||||
+
|
||||
+module_i2c_driver(max6620_driver);
|
||||
+
|
||||
+static int __init max6620_init(void)
|
||||
+{
|
||||
+ return i2c_add_driver(&max6620_driver);
|
||||
+}
|
||||
+module_init(max6620_init);
|
||||
+
|
||||
+/**
|
||||
+ * sht21_init() - clean up driver
|
||||
+ *
|
||||
+ * Called when module is removed.
|
||||
+ */
|
||||
+static void __exit max6620_exit(void)
|
||||
+{
|
||||
+ i2c_del_driver(&max6620_driver);
|
||||
+}
|
||||
+module_exit(max6620_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Lucas Grunenberg");
|
||||
+MODULE_DESCRIPTION("MAX6620 sensor driver");
|
||||
+MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,26 @@
|
||||
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
|
||||
index 654a402..9714687 100644
|
||||
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
|
||||
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
|
||||
@@ -404,6 +404,9 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
|
||||
case X557_PHY_ID2:
|
||||
phy_type = ixgbe_phy_x550em_ext_t;
|
||||
break;
|
||||
+ case BCM54616S_E_PHY_ID:
|
||||
+ phy_type = ixgbe_phy_ext_1g_t;
|
||||
+ break;
|
||||
default:
|
||||
phy_type = ixgbe_phy_unknown;
|
||||
break;
|
||||
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
|
||||
index ffa0ee5..fb89b2b 100644
|
||||
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
|
||||
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
|
||||
@@ -1387,6 +1387,7 @@ struct ixgbe_thermal_sensor_data {
|
||||
#define QT2022_PHY_ID 0x0043A400
|
||||
#define ATH_PHY_ID 0x03429050
|
||||
#define AQ_FW_REV 0x20
|
||||
+#define BCM54616S_E_PHY_ID 0x03625D10
|
||||
|
||||
/* Special PHY Init Routine */
|
||||
#define IXGBE_PHY_INIT_OFFSET_NL 0x002B
|
||||
7
packages/base/any/kernels/4.19-lts/patches/series
Executable file
7
packages/base/any/kernels/4.19-lts/patches/series
Executable file
@@ -0,0 +1,7 @@
|
||||
0001-drivers-i2c-muxes-pca954x-deselect-on-exit.patch
|
||||
0002-driver-support-intel-igb-bcm5461S-phy.patch
|
||||
0003-drivers-net-ethernet-broadcom-tg3.patch
|
||||
driver-ixgbe-external-phy.patch
|
||||
driver-hwmon-max6620.patch
|
||||
driver-hwmon-max6620-fix-rpm-calc.patch
|
||||
driver-hwmon-max6620-update.patch
|
||||
Reference in New Issue
Block a user