📄 adm1026.c
字号:
/* adm1026.c - Part of lm_sensors, Linux kernel modules for hardware monitoring Copyright (C) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> Copyright (C) 2004 Justin Thiessen <jthiessen@penguincomputing.com> Chip details at: <http://www.analog.com/UploadedFiles/Data_Sheets/779263102ADM1026_a.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/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/i2c.h>#include <linux/i2c-sensor.h>#include <linux/i2c-vid.h>/* Addresses to scan */static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };/* Insmod parameters */SENSORS_INSMOD_1(adm1026);static int gpio_input[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; static int gpio_output[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };static int gpio_inverted[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };static int gpio_normal[17] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };static int gpio_fan[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };module_param_array(gpio_input,int,NULL,0);MODULE_PARM_DESC(gpio_input,"List of GPIO pins (0-16) to program as inputs");module_param_array(gpio_output,int,NULL,0);MODULE_PARM_DESC(gpio_output,"List of GPIO pins (0-16) to program as " "outputs");module_param_array(gpio_inverted,int,NULL,0);MODULE_PARM_DESC(gpio_inverted,"List of GPIO pins (0-16) to program as " "inverted");module_param_array(gpio_normal,int,NULL,0);MODULE_PARM_DESC(gpio_normal,"List of GPIO pins (0-16) to program as " "normal/non-inverted");module_param_array(gpio_fan,int,NULL,0);MODULE_PARM_DESC(gpio_fan,"List of GPIO pins (0-7) to program as fan tachs");/* Many ADM1026 constants specified below *//* The ADM1026 registers */#define ADM1026_REG_CONFIG1 0x00#define CFG1_MONITOR 0x01#define CFG1_INT_ENABLE 0x02#define CFG1_INT_CLEAR 0x04#define CFG1_AIN8_9 0x08#define CFG1_THERM_HOT 0x10#define CFG1_DAC_AFC 0x20#define CFG1_PWM_AFC 0x40#define CFG1_RESET 0x80#define ADM1026_REG_CONFIG2 0x01/* CONFIG2 controls FAN0/GPIO0 through FAN7/GPIO7 */#define ADM1026_REG_CONFIG3 0x07#define CFG3_GPIO16_ENABLE 0x01#define CFG3_CI_CLEAR 0x02#define CFG3_VREF_250 0x04#define CFG3_GPIO16_DIR 0x40#define CFG3_GPIO16_POL 0x80#define ADM1026_REG_E2CONFIG 0x13#define E2CFG_READ 0x01#define E2CFG_WRITE 0x02#define E2CFG_ERASE 0x04#define E2CFG_ROM 0x08#define E2CFG_CLK_EXT 0x80/* There are 10 general analog inputs and 7 dedicated inputs * They are: * 0 - 9 = AIN0 - AIN9 * 10 = Vbat * 11 = 3.3V Standby * 12 = 3.3V Main * 13 = +5V * 14 = Vccp (CPU core voltage) * 15 = +12V * 16 = -12V */static u16 ADM1026_REG_IN[] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x27, 0x29, 0x26, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f };static u16 ADM1026_REG_IN_MIN[] = { 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x6d, 0x49, 0x6b, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };static u16 ADM1026_REG_IN_MAX[] = { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x6c, 0x41, 0x6a, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 };/* Temperatures are: * 0 - Internal * 1 - External 1 * 2 - External 2 */static u16 ADM1026_REG_TEMP[] = { 0x1f, 0x28, 0x29 };static u16 ADM1026_REG_TEMP_MIN[] = { 0x69, 0x48, 0x49 };static u16 ADM1026_REG_TEMP_MAX[] = { 0x68, 0x40, 0x41 };static u16 ADM1026_REG_TEMP_TMIN[] = { 0x10, 0x11, 0x12 };static u16 ADM1026_REG_TEMP_THERM[] = { 0x0d, 0x0e, 0x0f };static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f };#define ADM1026_REG_FAN(nr) (0x38 + (nr))#define ADM1026_REG_FAN_MIN(nr) (0x60 + (nr))#define ADM1026_REG_FAN_DIV_0_3 0x02#define ADM1026_REG_FAN_DIV_4_7 0x03#define ADM1026_REG_DAC 0x04#define ADM1026_REG_PWM 0x05#define ADM1026_REG_GPIO_CFG_0_3 0x08#define ADM1026_REG_GPIO_CFG_4_7 0x09#define ADM1026_REG_GPIO_CFG_8_11 0x0a#define ADM1026_REG_GPIO_CFG_12_15 0x0b/* CFG_16 in REG_CFG3 */#define ADM1026_REG_GPIO_STATUS_0_7 0x24#define ADM1026_REG_GPIO_STATUS_8_15 0x25/* STATUS_16 in REG_STATUS4 */#define ADM1026_REG_GPIO_MASK_0_7 0x1c#define ADM1026_REG_GPIO_MASK_8_15 0x1d/* MASK_16 in REG_MASK4 */#define ADM1026_REG_COMPANY 0x16#define ADM1026_REG_VERSTEP 0x17/* These are the recognized values for the above regs */#define ADM1026_COMPANY_ANALOG_DEV 0x41#define ADM1026_VERSTEP_GENERIC 0x40#define ADM1026_VERSTEP_ADM1026 0x44#define ADM1026_REG_MASK1 0x18#define ADM1026_REG_MASK2 0x19#define ADM1026_REG_MASK3 0x1a#define ADM1026_REG_MASK4 0x1b#define ADM1026_REG_STATUS1 0x20#define ADM1026_REG_STATUS2 0x21#define ADM1026_REG_STATUS3 0x22#define ADM1026_REG_STATUS4 0x23#define ADM1026_FAN_ACTIVATION_TEMP_HYST -6#define ADM1026_FAN_CONTROL_TEMP_RANGE 20#define ADM1026_PWM_MAX 255/* Conversions. Rounding and limit checking is only done on the TO_REG * variants. Note that you should be a bit careful with which arguments * these macros are called: arguments may be evaluated more than once. *//* IN are scaled acording to built-in resistors. These are the * voltages corresponding to 3/4 of full scale (192 or 0xc0) * NOTE: The -12V input needs an additional factor to account * for the Vref pullup resistor. * NEG12_OFFSET = SCALE * Vref / V-192 - Vref * = 13875 * 2.50 / 1.875 - 2500 * = 16000 * * The values in this table are based on Table II, page 15 of the * datasheet. */static int adm1026_scaling[] = { /* .001 Volts */ 2250, 2250, 2250, 2250, 2250, 2250, 1875, 1875, 1875, 1875, 3000, 3330, 3330, 4995, 2250, 12000, 13875 };#define NEG12_OFFSET 16000#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from))#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,adm1026_scaling[n],192),\ 0,255))#define INS_FROM_REG(n,val) (SCALE(val,192,adm1026_scaling[n]))/* FAN speed is measured using 22.5kHz clock and counts for 2 pulses * and we assume a 2 pulse-per-rev fan tach signal * 22500 kHz * 60 (sec/min) * 2 (pulse) / 2 (pulse/rev) == 1350000 */#define FAN_TO_REG(val,div) ((val)<=0 ? 0xff : SENSORS_LIMIT(1350000/((val)*\ (div)),1,254)) #define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==0xff ? 0 : 1350000/((val)*\ (div)))#define DIV_FROM_REG(val) (1<<(val))#define DIV_TO_REG(val) ((val)>=8 ? 3 : (val)>=4 ? 2 : (val)>=2 ? 1 : 0)/* Temperature is reported in 1 degC increments */#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ -127,127))#define TEMP_FROM_REG(val) ((val) * 1000)#define OFFSET_TO_REG(val) (SENSORS_LIMIT(((val)+((val)<0 ? -500 : 500))/1000,\ -127,127))#define OFFSET_FROM_REG(val) ((val) * 1000)#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255))#define PWM_FROM_REG(val) (val)#define PWM_MIN_TO_REG(val) ((val) & 0xf0)#define PWM_MIN_FROM_REG(val) (((val) & 0xf0) + ((val) >> 4))/* Analog output is a voltage, and scaled to millivolts. The datasheet * indicates that the DAC could be used to drive the fans, but in our * example board (Arima HDAMA) it isn't connected to the fans at all. */#define DAC_TO_REG(val) (SENSORS_LIMIT(((((val)*255)+500)/2500),0,255)) #define DAC_FROM_REG(val) (((val)*2500)/255)/* Typically used with systems using a v9.1 VRM spec ? */#define ADM1026_INIT_VRM 91/* Chip sampling rates * * Some sensors are not updated more frequently than once per second * so it doesn't make sense to read them more often than that. * We cache the results and return the saved data if the driver * is called again before a second has elapsed. * * Also, there is significant configuration data for this chip * So, we keep the config data up to date in the cache * when it is written and only sample it once every 5 *minutes* */#define ADM1026_DATA_INTERVAL (1 * HZ)#define ADM1026_CONFIG_INTERVAL (5 * 60 * HZ)/* We allow for multiple chips in a single system. * * For each registered ADM1026, we need to keep state information * at client->data. The adm1026_data structure is dynamically * allocated, when a new client structure is allocated. */struct pwm_data { u8 pwm; u8 enable; u8 auto_pwm_min;};struct adm1026_data { struct i2c_client client; struct semaphore lock; enum chips type; struct semaphore update_lock; int valid; /* !=0 if following fields are valid */ unsigned long last_reading; /* In jiffies */ unsigned long last_config; /* In jiffies */ u8 in[17]; /* Register value */ u8 in_max[17]; /* Register value */ u8 in_min[17]; /* Register value */ s8 temp[3]; /* Register value */ s8 temp_min[3]; /* Register value */ s8 temp_max[3]; /* Register value */ s8 temp_tmin[3]; /* Register value */ s8 temp_crit[3]; /* Register value */ s8 temp_offset[3]; /* Register value */ u8 fan[8]; /* Register value */ u8 fan_min[8]; /* Register value */ u8 fan_div[8]; /* Decoded value */ struct pwm_data pwm1; /* Pwm control values */ int vid; /* Decoded value */ u8 vrm; /* VRM version */ u8 analog_out; /* Register value (DAC) */ long alarms; /* Register encoding, combined */ long alarm_mask; /* Register encoding, combined */ long gpio; /* Register encoding, combined */ long gpio_mask; /* Register encoding, combined */ u8 gpio_config[17]; /* Decoded value */ u8 config1; /* Register value */ u8 config2; /* Register value */ u8 config3; /* Register value */};static int adm1026_attach_adapter(struct i2c_adapter *adapter);static int adm1026_detect(struct i2c_adapter *adapter, int address, int kind);static int adm1026_detach_client(struct i2c_client *client);static int adm1026_read_value(struct i2c_client *client, u8 register);static int adm1026_write_value(struct i2c_client *client, u8 register, int value); static void adm1026_print_gpio(struct i2c_client *client);static void adm1026_fixup_gpio(struct i2c_client *client); static struct adm1026_data *adm1026_update_device(struct device *dev);static void adm1026_init_client(struct i2c_client *client);static struct i2c_driver adm1026_driver = { .owner = THIS_MODULE, .name = "adm1026", .flags = I2C_DF_NOTIFY, .attach_adapter = adm1026_attach_adapter, .detach_client = adm1026_detach_client,};static int adm1026_id;int adm1026_attach_adapter(struct i2c_adapter *adapter){ if (!(adapter->class & I2C_CLASS_HWMON)) { return 0; } return i2c_detect(adapter, &addr_data, adm1026_detect);}int adm1026_detach_client(struct i2c_client *client){ i2c_detach_client(client); kfree(client); return 0;}int adm1026_read_value(struct i2c_client *client, u8 reg){ int res; if (reg < 0x80) { /* "RAM" locations */ res = i2c_smbus_read_byte_data(client, reg) & 0xff; } else { /* EEPROM, do nothing */ res = 0; } return res;}int adm1026_write_value(struct i2c_client *client, u8 reg, int value){ int res; if (reg < 0x80) { /* "RAM" locations */ res = i2c_smbus_write_byte_data(client, reg, value); } else { /* EEPROM, do nothing */ res = 0; } return res;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -