From c4fde53ac586b26750ffb5d0eac297cc2f8e864a Mon Sep 17 00:00:00 2001 From: "Mark M. Hoffman" Date: Mon, 23 Aug 2004 21:57:11 +0000 Subject: [PATCH] Reordered functions to get rid of all unnecessary forward decls. This revision should be functionally equivalent with the previous, except one small bugfix: a typo in one of the smart tach SYSCTL numbers. The unified diff from this revision to the previous is nearly useless - sorry, it can't be helped. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@2672 7894878c-1315-0410-8ee3-d5d059ff63e0 --- kernel/chips/lm93.c | 2471 +++++++++++++++++++++---------------------- 1 file changed, 1192 insertions(+), 1279 deletions(-) diff --git a/kernel/chips/lm93.c b/kernel/chips/lm93.c index 43c7b4b1..924aab93 100644 --- a/kernel/chips/lm93.c +++ b/kernel/chips/lm93.c @@ -72,6 +72,162 @@ static int vccp_limit_type[2] /* = {0,0} */ ; MODULE_PARM(vccp_limit_type, "2-2i"); MODULE_PARM_DESC(vccp_limit_type, "Configures in7 and in8 limit modes"); +/* -- SENSORS SYSCTL START -- */ +/* volts * 100 */ +#define LM93_SYSCTL_IN1 1001 +#define LM93_SYSCTL_IN2 1002 +#define LM93_SYSCTL_IN3 1003 +#define LM93_SYSCTL_IN4 1004 +#define LM93_SYSCTL_IN5 1005 +#define LM93_SYSCTL_IN6 1006 +#define LM93_SYSCTL_IN7 1007 +#define LM93_SYSCTL_IN8 1008 +#define LM93_SYSCTL_IN9 1009 +#define LM93_SYSCTL_IN10 1010 +#define LM93_SYSCTL_IN11 1011 +#define LM93_SYSCTL_IN12 1012 +#define LM93_SYSCTL_IN13 1013 +#define LM93_SYSCTL_IN14 1014 +#define LM93_SYSCTL_IN15 1015 +#define LM93_SYSCTL_IN16 1016 + +/* degrees celcius * 10 */ +#define LM93_SYSCTL_TEMP1 1101 +#define LM93_SYSCTL_TEMP2 1102 +#define LM93_SYSCTL_TEMP3 1103 + +#define LM93_SYSCTL_TEMP1_AUTO_BASE 1111 +#define LM93_SYSCTL_TEMP2_AUTO_BASE 1112 +#define LM93_SYSCTL_TEMP3_AUTO_BASE 1113 + +#define LM93_SYSCTL_TEMP1_AUTO_OFFSETS 1121 +#define LM93_SYSCTL_TEMP2_AUTO_OFFSETS 1122 +#define LM93_SYSCTL_TEMP3_AUTO_OFFSETS 1123 + +#define LM93_SYSCTL_TEMP1_AUTO_BOOST 1131 +#define LM93_SYSCTL_TEMP2_AUTO_BOOST 1132 +#define LM93_SYSCTL_TEMP3_AUTO_BOOST 1133 + +#define LM93_SYSCTL_TEMP1_AUTO_BOOST_HYST 1141 +#define LM93_SYSCTL_TEMP2_AUTO_BOOST_HYST 1142 +#define LM93_SYSCTL_TEMP3_AUTO_BOOST_HYST 1143 + +/* 0 => off, 255 => 100% */ +#define LM93_SYSCTL_TEMP1_AUTO_PWM_MIN 1151 +#define LM93_SYSCTL_TEMP2_AUTO_PWM_MIN 1152 +#define LM93_SYSCTL_TEMP3_AUTO_PWM_MIN 1153 + +/* degrees celcius * 10 */ +#define LM93_SYSCTL_TEMP1_AUTO_OFFSET_HYST 1161 +#define LM93_SYSCTL_TEMP2_AUTO_OFFSET_HYST 1162 +#define LM93_SYSCTL_TEMP3_AUTO_OFFSET_HYST 1163 + +/* rotations/minute */ +#define LM93_SYSCTL_FAN1 1201 +#define LM93_SYSCTL_FAN2 1202 +#define LM93_SYSCTL_FAN3 1203 +#define LM93_SYSCTL_FAN4 1204 + +/* 1-2 => enable smart tach mode associated with this pwm #, or disable */ +#define LM93_SYSCTL_FAN1_SMART_TACH 1205 +#define LM93_SYSCTL_FAN2_SMART_TACH 1206 +#define LM93_SYSCTL_FAN3_SMART_TACH 1207 +#define LM93_SYSCTL_FAN4_SMART_TACH 1208 + +/* volts * 1000 */ +#define LM93_SYSCTL_VID1 1301 +#define LM93_SYSCTL_VID2 1302 + +/* 0 => off, 255 => 100% */ +#define LM93_SYSCTL_PWM1 1401 +#define LM93_SYSCTL_PWM2 1402 + +/* Hz */ +#define LM93_SYSCTL_PWM1_FREQ 1411 +#define LM93_SYSCTL_PWM2_FREQ 1412 + +/* bitvector */ +#define LM93_SYSCTL_PWM1_AUTO_CHANNELS 1421 +#define LM93_SYSCTL_PWM2_AUTO_CHANNELS 1422 + +/* Hz */ +#define LM93_SYSCTL_PWM1_AUTO_SPINUP_MIN 1431 +#define LM93_SYSCTL_PWM2_AUTO_SPINUP_MIN 1432 + +/* seconds */ +#define LM93_SYSCTL_PWM1_AUTO_SPINUP_TIME 1441 +#define LM93_SYSCTL_PWM2_AUTO_SPINUP_TIME 1442 + +/* seconds */ +#define LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP 1451 +#define LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP 1452 + +/* 0 => 0%, 255 => > 99.6% */ +#define LM93_SYSCTL_PROCHOT1 1501 +#define LM93_SYSCTL_PROCHOT2 1502 + +/* !0 => enable #PROCHOT logical short */ +#define LM93_SYSCTL_PROCHOT_SHORT 1503 + +/* 2 boolean enable/disable, 3rd value indicates duty cycle */ +#define LM93_SYSCTL_PROCHOT_OVERRIDE 1504 + +/* 2 values, 0-9 */ +#define LM93_SYSCTL_PROCHOT_INTERVAL 1505 + +/* GPIO input (bitmask) */ +#define LM93_SYSCTL_GPIO 1601 + +/* #VRDHOT input (boolean) */ +#define LM93_SYSCTL_VRDHOT1 1701 +#define LM93_SYSCTL_VRDHOT2 1702 + +/* alarms (bitmask) */ +#define LM93_SYSCTL_ALARMS 2001 + +/* alarm bitmask definitions + The LM93 has nearly 64 bits of error status... I've pared that down to + what I think is a useful subset in order to fit it into 32 bits. + + Especially note that the #VRD_HOT alarms are missing because we provide + that information as values in another /proc file. + + If libsensors is extended to support 64 bit values, this could be revisited. +*/ +#define LM93_ALARM_IN1 0x00000001 +#define LM93_ALARM_IN2 0x00000002 +#define LM93_ALARM_IN3 0x00000004 +#define LM93_ALARM_IN4 0x00000008 +#define LM93_ALARM_IN5 0x00000010 +#define LM93_ALARM_IN6 0x00000020 +#define LM93_ALARM_IN7 0x00000040 +#define LM93_ALARM_IN8 0x00000080 +#define LM93_ALARM_IN9 0x00000100 +#define LM93_ALARM_IN10 0x00000200 +#define LM93_ALARM_IN11 0x00000400 +#define LM93_ALARM_IN12 0x00000800 +#define LM93_ALARM_IN13 0x00001000 +#define LM93_ALARM_IN14 0x00002000 +#define LM93_ALARM_IN15 0x00004000 +#define LM93_ALARM_IN16 0x00008000 +#define LM93_ALARM_FAN1 0x00010000 +#define LM93_ALARM_FAN2 0x00020000 +#define LM93_ALARM_FAN3 0x00040000 +#define LM93_ALARM_FAN4 0x00080000 +#define LM93_ALARM_PH1_ERR 0x00100000 +#define LM93_ALARM_PH2_ERR 0x00200000 +#define LM93_ALARM_SCSI1_ERR 0x00400000 +#define LM93_ALARM_SCSI2_ERR 0x00800000 +#define LM93_ALARM_DVDDP1_ERR 0x01000000 +#define LM93_ALARM_DVDDP2_ERR 0x02000000 +#define LM93_ALARM_D1_ERR 0x04000000 +#define LM93_ALARM_D2_ERR 0x08000000 +#define LM93_ALARM_TEMP1 0x10000000 +#define LM93_ALARM_TEMP2 0x20000000 +#define LM93_ALARM_TEMP3 0x40000000 + +/* -- SENSORS SYSCTL END -- */ + /* SMBus capabilities */ #define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA) @@ -94,326 +250,6 @@ static const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = { { 0xfd, 9 }, }; -/* CONVERSIONS */ - -/* fan tach register to/from tach values */ -static const u8 lm93_tach_reg_to_value[16] = - { 0x00, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, - 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff, 0x00, 0x00 }; - -/* min, max, and nominal voltage readings, per channel (mV)*/ -static const unsigned long lm93_vin_val_min[16] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 3000, -}; -static const unsigned long lm93_vin_val_max[16] = { - 1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600, - 4400, 6667, 3333, 2625, 1312, 1312, 1236, 3600, -}; -/* -static const unsigned long lm93_vin_val_nom[16] = { - 927, 927, 927, 1200, 1500, 1500, 1200, 1200, - 3300, 5000, 2500, 1969, 984, 984, 309, 3300, -}; -*/ - -/* min, max, and nominal register values, per channel (u8) */ -static const u8 lm93_vin_reg_min[16] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, -}; -static const u8 lm93_vin_reg_max[16] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, -}; -/* -static const u8 lm93_vin_reg_nom[16] = { - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0, -}; -*/ - -/* IN: 1/100 V, limits determined by channel nr - REG: scaling determined by channel nr */ -static u8 LM93_IN_TO_REG(int nr, unsigned val) -{ - /* range limit */ - const long mV = SENSORS_LIMIT(val * 10, - lm93_vin_val_min[nr], lm93_vin_val_max[nr]); - - /* try not to lose too much precision here */ - const long uV = mV * 1000; - const long uV_max = lm93_vin_val_max[nr] * 1000; - const long uV_min = lm93_vin_val_min[nr] * 1000; - - /* convert */ - const long slope = (uV_max - uV_min) / - (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]); - const long intercept = uV_min - slope * lm93_vin_reg_min[nr]; - - u8 result = ((uV - intercept + (slope/2)) / slope); - result = SENSORS_LIMIT(result, - lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]); - return result; -} - -static unsigned LM93_IN_FROM_REG(int nr, u8 reg) -{ - const long uV_max = lm93_vin_val_max[nr] * 1000; - const long uV_min = lm93_vin_val_min[nr] * 1000; - - const long slope = (uV_max - uV_min) / - (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]); - const long intercept = uV_min - slope * lm93_vin_reg_min[nr]; - - return (slope * reg + intercept + 5000) / 10000; -} - -/* vid in mV , upper == 0 indicates low limit, otherwise upper limit - upper also determines which nibble of the register is returned - (the other nibble will be 0x0) */ -static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid) -{ - long uV_offset = vid * 1000 - val * 10000; - if (upper) { - uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000); - return (u8)((uV_offset / 12500 - 1) << 4); - } else { - uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000); - return (u8)((uV_offset / -25000 - 1) << 0); - } -} - -/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */ -static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid) -{ - const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) : - (((reg >> 0 & 0x0f) + 1) * -25000); - const long uV_vid = vid * 1000; - return (uV_vid + uV_offset + 5000) / 10000; -} - -#define LM93_TEMP_MIN (-1280) -#define LM93_TEMP_MAX ( 1270) - -/* TEMP: 1/10 degrees C (-128C to +127C) - REG: 1C/bit, two's complement */ -static u8 LM93_TEMP_TO_REG(int temp) -{ - int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX); - ntemp += (ntemp<0 ? -5 : 5); - return (u8)(ntemp / 10); -} - -static int LM93_TEMP_FROM_REG(u8 reg) -{ - return (s8)reg * 10; -} - -/* Determine 4-bit temperature offset resolution */ -static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr) -{ - /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ - return sfc2 & (nr < 2 ? 0x10 : 0x20); -} - -#define LM93_TEMP_OFFSET_MIN ( 0) -#define LM93_TEMP_OFFSET_MAX0 (150) -#define LM93_TEMP_OFFSET_MAX1 ( 75) - -/* This function is common to all 4-bit temperature offsets - returns 4 bits right justified - mode 0 => 1C/bit, mode !0 => 0.5C/bit */ -static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode) -{ - int factor = mode ? 5 : 10; - - off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN, - mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0); - return (u8)((off + factor/2) / factor); -} - -/* This function is common to all 4-bit temperature offsets - reg is 4 bits right justified - mode 0 => 1C/bit, mode !0 => 0.5C/bit */ -static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode) -{ - return (reg & 0x0f) * (mode ? 5 : 10); -} - -/* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero)) - REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero) - 0 <= nr <= 3 */ -static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode) -{ - u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode); - - /* temp1-temp2 (nr=0,1) use lower nibble */ - if (nr < 2) - return (old & 0xf0) | (new & 0x0f); - - /* temp3-temp4 (nr=2,3) use upper nibble */ - else - return (new << 4 & 0xf0) | (old & 0x0f); -} - -/* 0 <= nr <= 3 */ -static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode) -{ - /* temp1-temp2 (nr=0,1) use lower nibble */ - if (nr < 2) - return LM93_TEMP_OFFSET_FROM_REG(reg & 0x0f, mode); - - /* temp3-temp4 (nr=2,3) use upper nibble */ - else - return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode); -} - -/* RPM: (82.5 to 1350000) - REG: 14-bits, LE, *left* justified */ -static u16 LM93_FAN_TO_REG(long rpm) -{ - u16 count, regs; - - if (rpm == 0) { - count = 0x3fff; - } else { - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe); - } - - regs = count << 2; - return cpu_to_le16(regs); -} - -static int LM93_FAN_FROM_REG(u16 regs) -{ - const u16 count = le16_to_cpu(regs) >> 2; - return count==0 ? -1 : count==0x3fff ? 0: 1350000 / count; -} - -/* VID: mV - REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 */ -static int LM93_VID_FROM_REG(u8 reg) -{ - return vid_from_reg((reg & 0x3f), 100); -} - -/* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6% - * REG: (same) */ -static u8 LM93_PROCHOT_TO_REG(long prochot) -{ - prochot = SENSORS_LIMIT(prochot, 0, 255); - return (u8)prochot; -} - -/* PROCHOT-OVERRIDE; 0-15, 0 is 6.25%, 15 is 99.88% - * REG: (same) */ -static u8 LM93_PROCHOT_OVERRIDE_TO_REG(int force1, int force2, long prochot) -{ - u8 result = 0; - - result |= force1 ? 0x80 : 0x00; - result |= force2 ? 0x40 : 0x00; - prochot = SENSORS_LIMIT(prochot, 0, 15); - result |= prochot; - return result; -} - -/* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds) - * REG: 0-9 as mapped below */ -static int lm93_interval_map[10] = { - 73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200, -}; - -static int LM93_INTERVAL_FROM_REG(u8 reg) -{ - return lm93_interval_map[reg & 0x0f]; -} - -/* round up to nearest match */ -static u8 LM93_INTERVAL_TO_REG(long interval) -{ - int i; - for (i = 0; i < 9; i++) - if (interval <= lm93_interval_map[i]) - break; - - /* can fall through with i==9 */ - return (u8)i; -} - -/* PWM: 0-255 per sensors documentation - REG: 0-13 as mapped below... right justified */ -typedef enum { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ } pwm_freq_t; -static int lm93_pwm_map[2][14] = { - { - 0x00, /* 0.00% */ 0x40, /* 25.00% */ - 0x50, /* 31.25% */ 0x60, /* 37.50% */ - 0x70, /* 43.75% */ 0x80, /* 50.00% */ - 0x90, /* 56.25% */ 0xa0, /* 62.50% */ - 0xb0, /* 68.75% */ 0xc0, /* 75.00% */ - 0xd0, /* 81.25% */ 0xe0, /* 87.50% */ - 0xf0, /* 93.75% */ 0xff, /* 100.00% */ - }, - { - 0x00, /* 0.00% */ 0x40, /* 25.00% */ - 0x49, /* 28.57% */ 0x52, /* 32.14% */ - 0x5b, /* 35.71% */ 0x64, /* 39.29% */ - 0x6d, /* 42.86% */ 0x76, /* 46.43% */ - 0x80, /* 50.00% */ 0x89, /* 53.57% */ - 0x92, /* 57.14% */ 0xb6, /* 71.43% */ - 0xdb, /* 85.71% */ 0xff, /* 100.00% */ - }, -}; - -static int LM93_PWM_FROM_REG(u8 reg, pwm_freq_t freq) -{ - return lm93_pwm_map[freq][reg & 0x0f]; -} - -/* round up to nearest match */ -static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq) -{ - int i; - for (i = 0; i < 13; i++) - if (pwm <= lm93_pwm_map[freq][i]) - break; - - /* can fall through with i==13 */ - return (u8)i; -} - -/* PWM FREQ: HZ - REG: 0-7 as mapped below */ -static int lm93_pwm_freq_map[8] = { - 22500, 96, 84, 72, 60, 48, 36, 12 -}; - -static int LM93_PWM_FREQ_FROM_REG(u8 reg) -{ - return lm93_pwm_freq_map[reg & 0x07]; -} - -/* round up to nearest match */ -static u8 LM93_PWM_FREQ_TO_REG(int freq) -{ - int i; - for (i = 7; i > 0; i--) - if (freq <= lm93_pwm_freq_map[i]) - break; - - /* can fall through with i==0 */ - return (u8)i; -} - -/* GPIO: 0-255, GPIO0 is LSB - * REG: inverted */ -static unsigned LM93_GPI_FROM_REG(u8 reg) -{ - return ~reg & 0xff; -} - /* ALARMS: SYSCTL format described further below REG: 64 bits in 8 registers, as immediately below */ struct block1_t { @@ -427,18 +263,8 @@ struct block1_t { u8 fan_status; }; -static unsigned LM93_ALARMS_FROM_REG(struct block1_t b1) -{ - unsigned result; - result = b1.host_status_2; - result |= b1.host_status_3 << 8; - result |= (b1.fan_status & 0x04) << 16; - result |= (b1.p1_prochot_status & 0x80) << 13; - result |= (b1.p2_prochot_status & 0x80) << 14; - result |= (b1.host_status_4 & 0xfc) << 20; - result |= (b1.host_status_1 & 0x07) << 28; - return result; -} +/* unique ID for each LM93 detected */ +static int lm93_id = 0; /* For each registered client, we need to keep some data in memory. That data is pointed to by client->data. The structure itself is dynamically @@ -533,548 +359,6 @@ struct lm93_data { u8 pwm_override[2]; }; - -static int lm93_attach_adapter(struct i2c_adapter *adapter); -static int lm93_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); -static int lm93_detach_client(struct i2c_client *client); - -static u8 lm93_read_byte(struct i2c_client *client, u8 register); -static int lm93_write_byte(struct i2c_client *client, u8 register, u8 value); -static u16 lm93_read_word(struct i2c_client *client, u8 register); -static int lm93_write_word(struct i2c_client *client, u8 register, u16 value); -static void lm93_update_client(struct i2c_client *client); -static void lm93_update_client_full(struct lm93_data *data, - struct i2c_client *client); -static void lm93_update_client_min (struct lm93_data *data, - struct i2c_client *client); - -static void lm93_init_client(struct i2c_client *client); - - -static void lm93_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); -static void lm93_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_fan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_pwm(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_pwm_freq(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_pwm_auto_chan(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_pwm_auto_spinup_min(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_pwm_auto_spinup_time(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_pwm_auto_ramp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_temp_auto_base(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_temp_auto_offsets(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_temp_auto_boost(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_temp_auto_boost_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_temp_auto_pwm_min(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_temp_auto_offset_hyst(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_fan_smart_tach(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_vid(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_prochot(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_prochot_short(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_prochot_override(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_prochot_interval(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_vrdhot(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_gpio(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void lm93_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); - -static struct i2c_driver lm93_driver = { - .owner = THIS_MODULE, - .name = "LM93 sensor driver", - .id = I2C_DRIVERID_LM93, - .flags = I2C_DF_NOTIFY, - .attach_adapter = lm93_attach_adapter, - .detach_client = lm93_detach_client, -}; - -/* unique ID for each LM93 detected */ -static int lm93_id = 0; - -/* -- SENSORS SYSCTL START -- */ -/* volts * 100 */ -#define LM93_SYSCTL_IN1 1001 -#define LM93_SYSCTL_IN2 1002 -#define LM93_SYSCTL_IN3 1003 -#define LM93_SYSCTL_IN4 1004 -#define LM93_SYSCTL_IN5 1005 -#define LM93_SYSCTL_IN6 1006 -#define LM93_SYSCTL_IN7 1007 -#define LM93_SYSCTL_IN8 1008 -#define LM93_SYSCTL_IN9 1009 -#define LM93_SYSCTL_IN10 1010 -#define LM93_SYSCTL_IN11 1011 -#define LM93_SYSCTL_IN12 1012 -#define LM93_SYSCTL_IN13 1013 -#define LM93_SYSCTL_IN14 1014 -#define LM93_SYSCTL_IN15 1015 -#define LM93_SYSCTL_IN16 1016 - -/* degrees celcius * 10 */ -#define LM93_SYSCTL_TEMP1 1101 -#define LM93_SYSCTL_TEMP2 1102 -#define LM93_SYSCTL_TEMP3 1103 - -#define LM93_SYSCTL_TEMP1_AUTO_BASE 1111 -#define LM93_SYSCTL_TEMP2_AUTO_BASE 1112 -#define LM93_SYSCTL_TEMP3_AUTO_BASE 1113 - -#define LM93_SYSCTL_TEMP1_AUTO_OFFSETS 1121 -#define LM93_SYSCTL_TEMP2_AUTO_OFFSETS 1122 -#define LM93_SYSCTL_TEMP3_AUTO_OFFSETS 1123 - -#define LM93_SYSCTL_TEMP1_AUTO_BOOST 1131 -#define LM93_SYSCTL_TEMP2_AUTO_BOOST 1132 -#define LM93_SYSCTL_TEMP3_AUTO_BOOST 1133 - -#define LM93_SYSCTL_TEMP1_AUTO_BOOST_HYST 1141 -#define LM93_SYSCTL_TEMP2_AUTO_BOOST_HYST 1142 -#define LM93_SYSCTL_TEMP3_AUTO_BOOST_HYST 1143 - -/* 0 => off, 255 => 100% */ -#define LM93_SYSCTL_TEMP1_AUTO_PWM_MIN 1151 -#define LM93_SYSCTL_TEMP2_AUTO_PWM_MIN 1152 -#define LM93_SYSCTL_TEMP3_AUTO_PWM_MIN 1153 - -/* degrees celcius * 10 */ -#define LM93_SYSCTL_TEMP1_AUTO_OFFSET_HYST 1161 -#define LM93_SYSCTL_TEMP2_AUTO_OFFSET_HYST 1162 -#define LM93_SYSCTL_TEMP3_AUTO_OFFSET_HYST 1163 - -/* rotations/minute */ -#define LM93_SYSCTL_FAN1 1201 -#define LM93_SYSCTL_FAN2 1202 -#define LM93_SYSCTL_FAN3 1203 -#define LM93_SYSCTL_FAN4 1204 - -/* 1-2 => enable smart tach mode associated with this pwm #, or disable */ -#define LM93_SYSCTL_FAN1_SMART_TACH 1205 -#define LM93_SYSCTL_FAN2_SMART_TACH 1205 -#define LM93_SYSCTL_FAN3_SMART_TACH 1207 -#define LM93_SYSCTL_FAN4_SMART_TACH 1208 - -/* volts * 1000 */ -#define LM93_SYSCTL_VID1 1301 -#define LM93_SYSCTL_VID2 1302 - -/* 0 => off, 255 => 100% */ -#define LM93_SYSCTL_PWM1 1401 -#define LM93_SYSCTL_PWM2 1402 - -/* Hz */ -#define LM93_SYSCTL_PWM1_FREQ 1411 -#define LM93_SYSCTL_PWM2_FREQ 1412 - -/* bitvector */ -#define LM93_SYSCTL_PWM1_AUTO_CHANNELS 1421 -#define LM93_SYSCTL_PWM2_AUTO_CHANNELS 1422 - -/* Hz */ -#define LM93_SYSCTL_PWM1_AUTO_SPINUP_MIN 1431 -#define LM93_SYSCTL_PWM2_AUTO_SPINUP_MIN 1432 - -/* seconds */ -#define LM93_SYSCTL_PWM1_AUTO_SPINUP_TIME 1441 -#define LM93_SYSCTL_PWM2_AUTO_SPINUP_TIME 1442 - -/* seconds */ -#define LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP 1451 -#define LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP 1452 - -/* 0 => 0%, 255 => > 99.6% */ -#define LM93_SYSCTL_PROCHOT1 1501 -#define LM93_SYSCTL_PROCHOT2 1502 - -/* !0 => enable #PROCHOT logical short */ -#define LM93_SYSCTL_PROCHOT_SHORT 1503 - -/* 2 boolean enable/disable, 3rd value indicates duty cycle */ -#define LM93_SYSCTL_PROCHOT_OVERRIDE 1504 - -/* 2 values, 0-9 */ -#define LM93_SYSCTL_PROCHOT_INTERVAL 1505 - -/* GPIO input (bitmask) */ -#define LM93_SYSCTL_GPIO 1601 - -/* #VRDHOT input (boolean) */ -#define LM93_SYSCTL_VRDHOT1 1701 -#define LM93_SYSCTL_VRDHOT2 1702 - -/* alarms (bitmask) */ -#define LM93_SYSCTL_ALARMS 2001 /* bitvector */ - -/* alarm bitmask definitions - The LM93 has nearly 64 bits of error status... I've pared that down to - what I think is a useful subset in order to fit it into 32 bits. - - Especially note that the #VRD_HOT alarms are missing because we provide - that information as values in another /proc file. - - If libsensors is extended to support 64 bit values, this could be revisited. -*/ -#define LM93_ALARM_IN1 0x00000001 -#define LM93_ALARM_IN2 0x00000002 -#define LM93_ALARM_IN3 0x00000004 -#define LM93_ALARM_IN4 0x00000008 -#define LM93_ALARM_IN5 0x00000010 -#define LM93_ALARM_IN6 0x00000020 -#define LM93_ALARM_IN7 0x00000040 -#define LM93_ALARM_IN8 0x00000080 -#define LM93_ALARM_IN9 0x00000100 -#define LM93_ALARM_IN10 0x00000200 -#define LM93_ALARM_IN11 0x00000400 -#define LM93_ALARM_IN12 0x00000800 -#define LM93_ALARM_IN13 0x00001000 -#define LM93_ALARM_IN14 0x00002000 -#define LM93_ALARM_IN15 0x00004000 -#define LM93_ALARM_IN16 0x00008000 -#define LM93_ALARM_FAN1 0x00010000 -#define LM93_ALARM_FAN2 0x00020000 -#define LM93_ALARM_FAN3 0x00040000 -#define LM93_ALARM_FAN4 0x00080000 -#define LM93_ALARM_PH1_ERR 0x00100000 -#define LM93_ALARM_PH2_ERR 0x00200000 -#define LM93_ALARM_SCSI1_ERR 0x00400000 -#define LM93_ALARM_SCSI2_ERR 0x00800000 -#define LM93_ALARM_DVDDP1_ERR 0x01000000 -#define LM93_ALARM_DVDDP2_ERR 0x02000000 -#define LM93_ALARM_D1_ERR 0x04000000 -#define LM93_ALARM_D2_ERR 0x08000000 -#define LM93_ALARM_TEMP1 0x10000000 -#define LM93_ALARM_TEMP2 0x20000000 -#define LM93_ALARM_TEMP3 0x40000000 - -/* -- SENSORS SYSCTL END -- */ - -/* These files are created for each detected LM93. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ - -#define LM93_SYSCTL_IN(nr) {LM93_SYSCTL_IN##nr, "in" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_in} -#define LM93_SYSCTL_TEMP(nr) {LM93_SYSCTL_TEMP##nr, "temp" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_temp} -#define LM93_SYSCTL_TEMP_AUTO_BASE(nr) {LM93_SYSCTL_TEMP##nr##_AUTO_BASE, \ - "temp" #nr "_auto_base", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_temp_auto_base} -#define LM93_SYSCTL_TEMP_AUTO_OFFSETS(nr) {LM93_SYSCTL_TEMP##nr##_AUTO_OFFSETS,\ - "temp" #nr "_auto_offsets", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_temp_auto_offsets} -#define LM93_SYSCTL_TEMP_AUTO_BOOST(nr) { LM93_SYSCTL_TEMP##nr##_AUTO_BOOST, \ - "temp" #nr "_auto_boost", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_temp_auto_boost} -#define LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(nr) { \ - LM93_SYSCTL_TEMP##nr##_AUTO_BOOST_HYST, "temp" #nr "_auto_boost_hyst", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_temp_auto_boost_hyst} -#define LM93_SYSCTL_TEMP_AUTO_PWM_MIN(nr) { \ - LM93_SYSCTL_TEMP##nr##_AUTO_PWM_MIN, "temp" #nr "_auto_pwm_min", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_temp_auto_pwm_min} -#define LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(nr) { \ - LM93_SYSCTL_TEMP##nr##_AUTO_OFFSET_HYST,"temp" #nr "_auto_offset_hyst",\ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_temp_auto_offset_hyst} -#define LM93_SYSCTL_PWM(nr) {LM93_SYSCTL_PWM##nr, "pwm" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_pwm} -#define LM93_SYSCTL_PWM_FREQ(nr) {LM93_SYSCTL_PWM##nr##_FREQ, \ - "pwm" #nr "_freq", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_pwm_freq} -#define LM93_SYSCTL_PWM_AUTO_CHAN(nr) {LM93_SYSCTL_PWM##nr##_AUTO_CHANNELS, \ - "pwm" #nr "_auto_channels", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_pwm_auto_chan} -#define LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(nr) { \ - LM93_SYSCTL_PWM##nr##_AUTO_SPINUP_MIN, "pwm" #nr "_auto_spinup_min", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_pwm_auto_spinup_min} -#define LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(nr) { \ - LM93_SYSCTL_PWM##nr##_AUTO_SPINUP_TIME, "pwm" #nr "_auto_spinup_time", \ - NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ - &lm93_pwm_auto_spinup_time} -#define LM93_SYSCTL_FAN(nr) {LM93_SYSCTL_FAN##nr, "fan" #nr, NULL, 0, \ - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_fan} -#define LM93_SYSCTL_VID(nr) {LM93_SYSCTL_VID##nr, "vid" #nr, NULL, 0, \ - 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_vid} -#define LM93_SYSCTL_PROCHOT(nr) {LM93_SYSCTL_PROCHOT##nr, "prochot" #nr, NULL, \ - 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot} -#define LM93_SYSCTL_VRDHOT(nr) {LM93_SYSCTL_VRDHOT##nr, "vrdhot" #nr, NULL, \ - 0, 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_vrdhot} -#define LM93_SYSCTL_FAN_SMART_TACH(nr) {LM93_SYSCTL_FAN##nr##_SMART_TACH, \ - "fan" #nr "_smart_tach", NULL, 0, 0644, NULL, &i2c_proc_real, \ - &i2c_sysctl_real, NULL, &lm93_fan_smart_tach} -static ctl_table lm93_dir_table_template[] = { - LM93_SYSCTL_IN(1), - LM93_SYSCTL_IN(2), - LM93_SYSCTL_IN(3), - LM93_SYSCTL_IN(4), - LM93_SYSCTL_IN(5), - LM93_SYSCTL_IN(6), - LM93_SYSCTL_IN(7), - LM93_SYSCTL_IN(8), - LM93_SYSCTL_IN(9), - LM93_SYSCTL_IN(10), - LM93_SYSCTL_IN(11), - LM93_SYSCTL_IN(12), - LM93_SYSCTL_IN(13), - LM93_SYSCTL_IN(14), - LM93_SYSCTL_IN(15), - LM93_SYSCTL_IN(16), - - LM93_SYSCTL_TEMP(1), - LM93_SYSCTL_TEMP(2), - LM93_SYSCTL_TEMP(3), - - LM93_SYSCTL_TEMP_AUTO_BASE(1), - LM93_SYSCTL_TEMP_AUTO_BASE(2), - LM93_SYSCTL_TEMP_AUTO_BASE(3), - - LM93_SYSCTL_TEMP_AUTO_OFFSETS(1), - LM93_SYSCTL_TEMP_AUTO_OFFSETS(2), - LM93_SYSCTL_TEMP_AUTO_OFFSETS(3), - - LM93_SYSCTL_TEMP_AUTO_BOOST(1), - LM93_SYSCTL_TEMP_AUTO_BOOST(2), - LM93_SYSCTL_TEMP_AUTO_BOOST(3), - - LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(1), - LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(2), - LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(3), - - LM93_SYSCTL_TEMP_AUTO_PWM_MIN(1), - LM93_SYSCTL_TEMP_AUTO_PWM_MIN(2), - LM93_SYSCTL_TEMP_AUTO_PWM_MIN(3), - - LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(1), - LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(2), - LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(3), - - LM93_SYSCTL_FAN(1), - LM93_SYSCTL_FAN(2), - LM93_SYSCTL_FAN(3), - LM93_SYSCTL_FAN(4), - - LM93_SYSCTL_FAN_SMART_TACH(1), - LM93_SYSCTL_FAN_SMART_TACH(2), - LM93_SYSCTL_FAN_SMART_TACH(3), - LM93_SYSCTL_FAN_SMART_TACH(4), - - LM93_SYSCTL_PWM(1), - LM93_SYSCTL_PWM(2), - - LM93_SYSCTL_PWM_FREQ(1), - LM93_SYSCTL_PWM_FREQ(2), - - LM93_SYSCTL_PWM_AUTO_CHAN(1), - LM93_SYSCTL_PWM_AUTO_CHAN(2), - - LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(1), - LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(2), - - LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(1), - LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(2), - - {LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP, "pwm_auto_prochot_ramp", NULL, 0, - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, - &lm93_pwm_auto_ramp}, - - {LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP, "pwm_auto_vrdhot_ramp", NULL, 0, - 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, - &lm93_pwm_auto_ramp}, - - LM93_SYSCTL_VID(1), - LM93_SYSCTL_VID(2), - - LM93_SYSCTL_PROCHOT(1), - LM93_SYSCTL_PROCHOT(2), - - {LM93_SYSCTL_PROCHOT_SHORT, "prochot_short", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_short}, - - {LM93_SYSCTL_PROCHOT_OVERRIDE, "prochot_override", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_override}, - - {LM93_SYSCTL_PROCHOT_INTERVAL, "prochot_interval", NULL, 0, 0644, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_interval}, - - LM93_SYSCTL_VRDHOT(1), - LM93_SYSCTL_VRDHOT(2), - - {LM93_SYSCTL_GPIO, "gpio", NULL, 0, 0444, NULL, - &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_gpio}, - - {LM93_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm93_alarms}, - - {0} -}; - - -/* This function is called when: - * lm93_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm93_driver is still present) */ -static int lm93_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_detect(adapter, &addr_data, lm93_detect); -} - -/* This function is called by i2c_detect */ -int lm93_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) -{ - int err, func; - struct lm93_data *data; - struct i2c_client *client; - void (*update)(struct lm93_data *, struct i2c_client *); - - /* lm93 is SMBus only */ - if (i2c_is_isa_adapter(adapter)) { - pr_debug("lm93.o: detect failed, " - "cannot attach to legacy adapter!\n"); - err = -ENODEV; - goto ERROR0; - } - - /* choose update routine based on bus capabilities */ - func = i2c_get_functionality(adapter); - - if ( ((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) && - (!disable_block) ) { - pr_debug("lm93.o: using SMBus block data transactions\n"); - update = lm93_update_client_full; - } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) { - pr_debug("lm93.o: disabled SMBus block data transactions\n"); - update = lm93_update_client_min; - } else { - pr_debug("lm93.o: detect failed, " - "smbus byte and/or word data not supported!\n"); - err = -ENODEV; - goto ERROR0; - } - - /* OK. For now, we presume we have a valid client. We now create the - client structure, even though we cannot fill it completely yet. - But it allows us to access lm78_{read,write}_value. */ - - if (!(data = kmalloc(sizeof(struct lm93_data), GFP_KERNEL))) { - pr_debug("lm93.o: detect failed, kmalloc failed!\n"); - err = -ENOMEM; - goto ERROR0; - } - - client = &data->client; - client->addr = address; - init_MUTEX(&data->lock); - client->data = data; - client->adapter = adapter; - client->driver = &lm93_driver; - client->flags = 0; - - /* detection */ - if (kind < 0) { - int mfr = lm93_read_byte(client, LM93_REG_MFR_ID); - - if (mfr != 0x01) { - pr_debug("lm93.o: detect failed, " - "bad manufacturer id 0x%02x!\n", mfr); - err = -ENODEV; - goto ERROR1; - } - } - - if (kind <= 0) { - int ver = lm93_read_byte(client, LM93_REG_VER); - - if ((ver == LM93_MFR_ID) || (ver == LM93_MFR_ID_PROTOTYPE)) { - kind = lm93; - } else { - pr_debug("lm93.o: detect failed, " - "bad version id 0x%02x!\n", ver); - if (kind == 0) - pr_debug("lm93.o: " - "(ignored 'force' parameter)\n"); - err = -ENODEV; - goto ERROR1; - } - } - - /* fill in remaining client fields */ - strcpy(client->name, "LM93 chip"); - client->id = lm93_id++; - pr_debug("lm93.o: assigning ID %d to %s at %d,0x%02x\n", client->id, - client->name, i2c_adapter_id(client->adapter), client->addr); - - /* housekeeping */ - data->type = kind; - data->valid = 0; - data->update = update; - init_MUTEX(&data->update_lock); - - /* tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(client))) - goto ERROR1; - - /* initialize the chip */ - lm93_init_client(client); - - /* register a new directory entry with module sensors */ - if ((data->sysctl_id = i2c_register_entry(client, "lm93", - lm93_dir_table_template)) < 0) { - err = data->sysctl_id; - goto ERROR2; - } - - return 0; - -ERROR2: - i2c_detach_client(client); -ERROR1: - kfree(data); -ERROR0: - return err; -} - -static int lm93_detach_client(struct i2c_client *client) -{ - int err; - struct lm93_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); - - if ((err = i2c_detach_client(client))) { - printk (KERN_ERR "lm93.o: Client deregistration failed; " - "client not detached.\n"); - return err; - } - - return 0; -} - #define MAX_RETRIES 5 static u8 lm93_read_byte(struct i2c_client *client, u8 reg) @@ -1175,38 +459,6 @@ static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values) } } -static void lm93_init_client(struct i2c_client *client) -{ - int i; - u8 reg = lm93_read_byte(client, LM93_REG_CONFIG); - - /* start monitoring */ - lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01); - - if (init) { - /* enable #ALERT pin */ - reg = lm93_read_byte(client, LM93_REG_CONFIG); - lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x08); - - /* enable ASF mode for BMC status registers */ - reg = lm93_read_byte(client, LM93_REG_STATUS_CONTROL); - lm93_write_byte(client, LM93_REG_STATUS_CONTROL, reg | 0x02); - - /* set sleep state to S0 */ - lm93_write_byte(client, LM93_REG_SLEEP_CONTROL, 0); - } - - /* spin until ready */ - for (i=0; i<20; i++) { - mdelay(10); - if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80) - return; - } - - printk(KERN_WARNING "lm93.o: timed out waiting for sensor " - "chip to signal ready!\n"); -} - static void lm93_update_client(struct i2c_client *client) { struct lm93_data *data = client->data; @@ -1392,19 +644,122 @@ static void lm93_update_client_min(struct lm93_data *data, lm93_update_client_common(data, client); } -/* The next few functions are the call-back functions of the /proc/sys and - sysctl files. Which function is used is defined in the ctl_table in - the extra1 field. - Each function must return the magnitude (power of 10 to divide the date - with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must - put a maximum of *nrels elements in results reflecting the data of this - file, and set *nrels to the number it actually put in it, if operation== - SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from - results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. - Note that on SENSORS_PROC_REAL_READ, I do not check whether results is - large enough (by checking the incoming value of *nrels). This is not very - good practice, but as long as you put less than about 5 values in results, - you can assume it is large enough. */ +/* VID: mV + REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 */ +static int LM93_VID_FROM_REG(u8 reg) +{ + return vid_from_reg((reg & 0x3f), 100); +} + +static void lm93_vid(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm93_data *data = client->data; + int nr = ctl_name - LM93_SYSCTL_VID1; + + if (0 > nr || nr > 1) + return; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 2; + else if (operation == SENSORS_PROC_REAL_READ) { + lm93_update_client(client); + results[0] = LM93_VID_FROM_REG(data->vid[nr]); + *nrels_mag = 1; + } +} + +/* min, max, and nominal voltage readings, per channel (mV)*/ +static const unsigned long lm93_vin_val_min[16] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3000, +}; +static const unsigned long lm93_vin_val_max[16] = { + 1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600, + 4400, 6667, 3333, 2625, 1312, 1312, 1236, 3600, +}; +/* +static const unsigned long lm93_vin_val_nom[16] = { + 927, 927, 927, 1200, 1500, 1500, 1200, 1200, + 3300, 5000, 2500, 1969, 984, 984, 309, 3300, +}; +*/ + +/* min, max, and nominal register values, per channel (u8) */ +static const u8 lm93_vin_reg_min[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, +}; +static const u8 lm93_vin_reg_max[16] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, +}; +/* +static const u8 lm93_vin_reg_nom[16] = { + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0, +}; +*/ + +/* IN: 1/100 V, limits determined by channel nr + REG: scaling determined by channel nr */ +static u8 LM93_IN_TO_REG(int nr, unsigned val) +{ + /* range limit */ + const long mV = SENSORS_LIMIT(val * 10, + lm93_vin_val_min[nr], lm93_vin_val_max[nr]); + + /* try not to lose too much precision here */ + const long uV = mV * 1000; + const long uV_max = lm93_vin_val_max[nr] * 1000; + const long uV_min = lm93_vin_val_min[nr] * 1000; + + /* convert */ + const long slope = (uV_max - uV_min) / + (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]); + const long intercept = uV_min - slope * lm93_vin_reg_min[nr]; + + u8 result = ((uV - intercept + (slope/2)) / slope); + result = SENSORS_LIMIT(result, + lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]); + return result; +} + +static unsigned LM93_IN_FROM_REG(int nr, u8 reg) +{ + const long uV_max = lm93_vin_val_max[nr] * 1000; + const long uV_min = lm93_vin_val_min[nr] * 1000; + + const long slope = (uV_max - uV_min) / + (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]); + const long intercept = uV_min - slope * lm93_vin_reg_min[nr]; + + return (slope * reg + intercept + 5000) / 10000; +} + +/* vid in mV , upper == 0 indicates low limit, otherwise upper limit + upper also determines which nibble of the register is returned + (the other nibble will be 0x0) */ +static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid) +{ + long uV_offset = vid * 1000 - val * 10000; + if (upper) { + uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000); + return (u8)((uV_offset / 12500 - 1) << 4); + } else { + uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000); + return (u8)((uV_offset / -25000 - 1) << 0); + } +} + +/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */ +static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid) +{ + const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) : + (((reg >> 0 & 0x0f) + 1) * -25000); + const long uV_vid = vid * 1000; + return (uV_vid + uV_offset + 5000) / 10000; +} static void lm93_in(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) @@ -1479,7 +834,50 @@ static void lm93_in(struct i2c_client *client, int operation, int ctl_name, } } -void lm93_temp(struct i2c_client *client, int operation, int ctl_name, +static unsigned LM93_ALARMS_FROM_REG(struct block1_t b1) +{ + unsigned result; + result = b1.host_status_2; + result |= b1.host_status_3 << 8; + result |= (b1.fan_status & 0x04) << 16; + result |= (b1.p1_prochot_status & 0x80) << 13; + result |= (b1.p2_prochot_status & 0x80) << 14; + result |= (b1.host_status_4 & 0xfc) << 20; + result |= (b1.host_status_1 & 0x07) << 28; + return result; +} + +static void lm93_alarms(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct lm93_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm93_update_client(client); + results[0] = LM93_ALARMS_FROM_REG(data->block1); + *nrels_mag = 1; + } +} + +#define LM93_TEMP_MIN (-1280) +#define LM93_TEMP_MAX ( 1270) + +/* TEMP: 1/10 degrees C (-128C to +127C) + REG: 1C/bit, two's complement */ +static u8 LM93_TEMP_TO_REG(int temp) +{ + int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX); + ntemp += (ntemp<0 ? -5 : 5); + return (u8)(ntemp / 10); +} + +static int LM93_TEMP_FROM_REG(u8 reg) +{ + return (s8)reg * 10; +} + +static void lm93_temp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; @@ -1512,33 +910,66 @@ void lm93_temp(struct i2c_client *client, int operation, int ctl_name, } } -void lm93_temp_auto_base(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) +/* Determine 4-bit temperature offset resolution */ +static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr) { - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_BASE; - - if (0 > nr || nr > 2) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_TEMP_FROM_REG(data->block10.base[nr]); - *nrels_mag = 1; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->block10.base[nr] = LM93_TEMP_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_TEMP_BASE(nr), - data->block10.base[nr]); - } - up(&data->update_lock); - } + /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ + return sfc2 & (nr < 2 ? 0x10 : 0x20); } -void lm93_temp_auto_offsets(struct i2c_client *client, int operation, +#define LM93_TEMP_OFFSET_MIN ( 0) +#define LM93_TEMP_OFFSET_MAX0 (150) +#define LM93_TEMP_OFFSET_MAX1 ( 75) + +/* This function is common to all 4-bit temperature offsets + returns 4 bits right justified + mode 0 => 1C/bit, mode !0 => 0.5C/bit */ +static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode) +{ + int factor = mode ? 5 : 10; + + off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN, + mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0); + return (u8)((off + factor/2) / factor); +} + +/* This function is common to all 4-bit temperature offsets + reg is 4 bits right justified + mode 0 => 1C/bit, mode !0 => 0.5C/bit */ +static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode) +{ + return (reg & 0x0f) * (mode ? 5 : 10); +} + +/* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero)) + REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero) + 0 <= nr <= 3 */ +static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode) +{ + u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode); + + /* temp1-temp2 (nr=0,1) use lower nibble */ + if (nr < 2) + return (old & 0xf0) | (new & 0x0f); + + /* temp3-temp4 (nr=2,3) use upper nibble */ + else + return (new << 4 & 0xf0) | (old & 0x0f); +} + +/* 0 <= nr <= 3 */ +static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode) +{ + /* temp1-temp2 (nr=0,1) use lower nibble */ + if (nr < 2) + return LM93_TEMP_OFFSET_FROM_REG(reg & 0x0f, mode); + + /* temp3-temp4 (nr=2,3) use upper nibble */ + else + return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode); +} + +static void lm93_temp_auto_offsets(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; @@ -1584,7 +1015,456 @@ void lm93_temp_auto_offsets(struct i2c_client *client, int operation, } } -void lm93_temp_auto_boost(struct i2c_client *client, int operation, +/* RPM: (82.5 to 1350000) + REG: 14-bits, LE, *left* justified */ +static u16 LM93_FAN_TO_REG(long rpm) +{ + u16 count, regs; + + if (rpm == 0) { + count = 0x3fff; + } else { + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe); + } + + regs = count << 2; + return cpu_to_le16(regs); +} + +static int LM93_FAN_FROM_REG(u16 regs) +{ + const u16 count = le16_to_cpu(regs) >> 2; + return count==0 ? -1 : count==0x3fff ? 0: 1350000 / count; +} + +static void lm93_fan(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm93_data *data = client->data; + int nr = ctl_name - LM93_SYSCTL_FAN1; + + if (0 > nr || nr > 3) + return; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm93_update_client(client); + results[0] = LM93_FAN_FROM_REG(data->block8[nr]); /* min */ + results[1] = LM93_FAN_FROM_REG(data->block5[nr]); /* val */ + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + down(&data->update_lock); + data->block8[nr] = LM93_FAN_TO_REG(results[0]); + lm93_write_word(client, LM93_REG_FAN_MIN(nr), + data->block8[nr]); + up(&data->update_lock); + } + } +} + +/* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6% + * REG: (same) */ +static u8 LM93_PROCHOT_TO_REG(long prochot) +{ + prochot = SENSORS_LIMIT(prochot, 0, 255); + return (u8)prochot; +} + +static void lm93_prochot(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct lm93_data *data = client->data; + int nr = ctl_name - LM93_SYSCTL_PROCHOT1; + + if (0 > nr || nr > 1) + return; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm93_update_client(client); + results[0] = data->prochot_max[nr]; + results[1] = data->block4[nr].avg; + results[2] = data->block4[nr].avg; + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag >= 1) { + data->prochot_max[nr] = LM93_PROCHOT_TO_REG(results[0]); + lm93_write_byte(client, LM93_REG_PROCHOT_MAX(nr), + data->prochot_max[nr]); + } + up(&data->update_lock); + } +} + +/* PROCHOT-OVERRIDE; 0-15, 0 is 6.25%, 15 is 99.88% + * REG: (same) */ +static u8 LM93_PROCHOT_OVERRIDE_TO_REG(int force1, int force2, long prochot) +{ + u8 result = 0; + + result |= force1 ? 0x80 : 0x00; + result |= force2 ? 0x40 : 0x00; + prochot = SENSORS_LIMIT(prochot, 0, 15); + result |= prochot; + return result; +} + +static void lm93_prochot_override(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct lm93_data *data = client->data; + + if (ctl_name != LM93_SYSCTL_PROCHOT_OVERRIDE) + return; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm93_update_client(client); + results[0] = (data->prochot_override & 0x80) ? 1 : 0; + results[1] = (data->prochot_override & 0x40) ? 1 : 0; + results[2] = data->prochot_override & 0x0f; + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + + /* grab old values */ + int force2 = (data->prochot_override & 0x40) ? 1 : 0; + int prochot = data->prochot_override & 0x0f; + + down(&data->update_lock); + if (*nrels_mag >= 3) { + data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( + results[0], results[1], results[2]); + } + if (*nrels_mag == 2) { + data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( + results[0], results[1], prochot); + } + if (*nrels_mag == 1) { + data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( + results[0], force2, prochot); + } + if (*nrels_mag >= 1) { + lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE, + data->prochot_override); + } + up(&data->update_lock); + } +} + +/* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds) + * REG: 0-9 as mapped below */ +static int lm93_interval_map[10] = { + 73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200, +}; + +static int LM93_INTERVAL_FROM_REG(u8 reg) +{ + return lm93_interval_map[reg & 0x0f]; +} + +/* round up to nearest match */ +static u8 LM93_INTERVAL_TO_REG(long interval) +{ + int i; + for (i = 0; i < 9; i++) + if (interval <= lm93_interval_map[i]) + break; + + /* can fall through with i==9 */ + return (u8)i; +} + +static void lm93_prochot_interval(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct lm93_data *data = client->data; + + if (ctl_name != LM93_SYSCTL_PROCHOT_INTERVAL) + return; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 2; + else if (operation == SENSORS_PROC_REAL_READ) { + lm93_update_client(client); + results[0] = LM93_INTERVAL_FROM_REG( + data->prochot_interval & 0x0f); + results[1] = LM93_INTERVAL_FROM_REG( + (data->prochot_interval & 0xf0) >> 4); + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + data->prochot_interval = lm93_read_byte(client, + LM93_REG_PROCHOT_INTERVAL); + if (*nrels_mag >= 2) { + data->prochot_interval = + (LM93_INTERVAL_TO_REG(results[1]) << 4) | + (data->prochot_interval & 0x0f); + } + if (*nrels_mag >= 1) { + data->prochot_interval = + (data->prochot_interval & 0xf0) | + LM93_INTERVAL_TO_REG(results[0]); + lm93_write_byte(client, LM93_REG_PROCHOT_INTERVAL, + data->prochot_interval); + } + up(&data->update_lock); + } +} + +/* PWM: 0-255 per sensors documentation + REG: 0-13 as mapped below... right justified */ +typedef enum { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ } pwm_freq_t; +static int lm93_pwm_map[2][14] = { + { + 0x00, /* 0.00% */ 0x40, /* 25.00% */ + 0x50, /* 31.25% */ 0x60, /* 37.50% */ + 0x70, /* 43.75% */ 0x80, /* 50.00% */ + 0x90, /* 56.25% */ 0xa0, /* 62.50% */ + 0xb0, /* 68.75% */ 0xc0, /* 75.00% */ + 0xd0, /* 81.25% */ 0xe0, /* 87.50% */ + 0xf0, /* 93.75% */ 0xff, /* 100.00% */ + }, + { + 0x00, /* 0.00% */ 0x40, /* 25.00% */ + 0x49, /* 28.57% */ 0x52, /* 32.14% */ + 0x5b, /* 35.71% */ 0x64, /* 39.29% */ + 0x6d, /* 42.86% */ 0x76, /* 46.43% */ + 0x80, /* 50.00% */ 0x89, /* 53.57% */ + 0x92, /* 57.14% */ 0xb6, /* 71.43% */ + 0xdb, /* 85.71% */ 0xff, /* 100.00% */ + }, +}; + +static int LM93_PWM_FROM_REG(u8 reg, pwm_freq_t freq) +{ + return lm93_pwm_map[freq][reg & 0x0f]; +} + +/* round up to nearest match */ +static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq) +{ + int i; + for (i = 0; i < 13; i++) + if (pwm <= lm93_pwm_map[freq][i]) + break; + + /* can fall through with i==13 */ + return (u8)i; +} + +static void lm93_pwm(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm93_data *data = client->data; + int nr = ctl_name - LM93_SYSCTL_PWM1; + u8 ctl2, ctl4; + + if (0 > nr || nr > 1) + return; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm93_update_client(client); + ctl2 = data->block9[nr][LM93_PWM_CTL2]; + ctl4 = data->block9[nr][LM93_PWM_CTL4]; + results[1] = (ctl2 & 0x01) ? 1 : 0; + ctl2 = ctl2 >> 4 & 0x0f; + if (results[1]) /* show user commanded value if enabled */ + results[0] = data->pwm_override[nr]; + else /* show present h/w value if manual pwm disabled */ + results[0] = LM93_PWM_FROM_REG(ctl2, (ctl4 & 0x07) ? + LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); + *nrels_mag = 2; + } + else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + down(&data->update_lock); + ctl2 = lm93_read_byte( + client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2)); + ctl4 = lm93_read_byte( + client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); + ctl2 = (ctl2 & 0x0f) | + LM93_PWM_TO_REG(results[0], (ctl4 & 0x07) ? + LM93_PWM_MAP_LO_FREQ : + LM93_PWM_MAP_HI_FREQ) << 4; + if (*nrels_mag >= 2) { + if (results[1]) + ctl2 |= 0x01; + else + ctl2 &= ~0x01; + } + /* save user commanded value */ + data->pwm_override[nr] = + LM93_PWM_FROM_REG(ctl2 >> 4 & 0x0f, + (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : + LM93_PWM_MAP_HI_FREQ); + lm93_write_byte(client, + LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2), ctl2); + up(&data->update_lock); + } + } +} + +/* PWM FREQ: HZ + REG: 0-7 as mapped below */ +static int lm93_pwm_freq_map[8] = { + 22500, 96, 84, 72, 60, 48, 36, 12 +}; + +static int LM93_PWM_FREQ_FROM_REG(u8 reg) +{ + return lm93_pwm_freq_map[reg & 0x07]; +} + +/* round up to nearest match */ +static u8 LM93_PWM_FREQ_TO_REG(int freq) +{ + int i; + for (i = 7; i > 0; i--) + if (freq <= lm93_pwm_freq_map[i]) + break; + + /* can fall through with i==0 */ + return (u8)i; +} + +/* helper function - must grab data->update_lock before calling + fan is 0-3, indicating fan1-fan4 */ +static void lm93_write_fan_smart_tach(struct i2c_client *client, + struct lm93_data *data, int fan, long value) +{ + /* insert the new mapping and write it out */ + data->sf_tach_to_pwm = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM); + data->sf_tach_to_pwm &= ~0x3 << fan * 2; + data->sf_tach_to_pwm |= value << fan * 2; + lm93_write_byte(client, LM93_REG_SF_TACH_TO_PWM, data->sf_tach_to_pwm); + + /* insert the enable bit and write it out */ + data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); + if (value) + data->sfc2 |= 1 << fan; + else + data->sfc2 &= ~1 << fan; + lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); +} + +/* helper function - must grab data->update_lock before calling + pwm is 0-1, indicating pwm1-pwm2 + this disables smart tach for all tach channels bound to the given pwm */ +static void lm93_disable_fan_smart_tach(struct i2c_client *client, + struct lm93_data *data, int pwm) +{ + int mapping = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM); + int mask; + + /* collapse the mapping into a mask of enable bits */ + mapping = (mapping >> pwm) & 0x55; + mask = mapping & 0x01; + mask |= (mapping & 0x04) >> 1; + mask |= (mapping & 0x10) >> 2; + mask |= (mapping & 0x40) >> 3; + + /* disable smart tach according to the mask */ + data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); + data->sfc2 &= ~mask; + lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); +} + +static void lm93_pwm_freq(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct lm93_data *data = client->data; + int nr = ctl_name - LM93_SYSCTL_PWM1_FREQ; + u8 ctl4; + + if (0 > nr || nr > 1) + return; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm93_update_client(client); + ctl4 = data->block9[nr][LM93_PWM_CTL4]; + results[0] = LM93_PWM_FREQ_FROM_REG(ctl4); + *nrels_mag = 1; + } + else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + down(&data->update_lock); + ctl4 = lm93_read_byte( client, + LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); + ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(results[0]); + data->block9[nr][LM93_PWM_CTL4] = ctl4; + + /* ctl4 == 0 -> 22.5KHz -> disable smart tach */ + if (!ctl4) + lm93_disable_fan_smart_tach(client, data, nr); + + lm93_write_byte(client, + LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4), ctl4); + up(&data->update_lock); + } + } +} + +/* GPIO: 0-255, GPIO0 is LSB + * REG: inverted */ +static unsigned LM93_GPI_FROM_REG(u8 reg) +{ + return ~reg & 0xff; +} + +static void lm93_gpio(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct lm93_data *data = client->data; + + if (ctl_name != LM93_SYSCTL_GPIO) + return; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + lm93_update_client(client); + results[0] = LM93_GPI_FROM_REG(data->gpi); + *nrels_mag = 1; + } +} + +static void lm93_temp_auto_base(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct lm93_data *data = client->data; + int nr = ctl_name - LM93_SYSCTL_TEMP1_AUTO_BASE; + + if (0 > nr || nr > 2) + return; /* ERROR */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + lm93_update_client(client); + results[0] = LM93_TEMP_FROM_REG(data->block10.base[nr]); + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + down(&data->update_lock); + if (*nrels_mag >= 1) { + data->block10.base[nr] = LM93_TEMP_TO_REG(results[0]); + lm93_write_byte(client, LM93_REG_TEMP_BASE(nr), + data->block10.base[nr]); + } + up(&data->update_lock); + } +} + +static void lm93_temp_auto_boost(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; @@ -1661,7 +1541,7 @@ static int LM93_AUTO_BOOST_HYST_FROM_REGS(struct lm93_data *data, int nr, LM93_TEMP_OFFSET_FROM_REG(reg, mode); } -void lm93_temp_auto_boost_hyst(struct i2c_client *client, int operation, +static void lm93_temp_auto_boost_hyst(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; @@ -1700,7 +1580,7 @@ void lm93_temp_auto_boost_hyst(struct i2c_client *client, int operation, } } -void lm93_temp_auto_pwm_min(struct i2c_client *client, int operation, +static void lm93_temp_auto_pwm_min(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; @@ -1737,7 +1617,7 @@ void lm93_temp_auto_pwm_min(struct i2c_client *client, int operation, } } -void lm93_temp_auto_offset_hyst(struct i2c_client *client, int operation, +static void lm93_temp_auto_offset_hyst(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; @@ -1780,51 +1660,6 @@ void lm93_temp_auto_offset_hyst(struct i2c_client *client, int operation, } } -void lm93_fan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_FAN1; - - if (0 > nr || nr > 3) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_FAN_FROM_REG(data->block8[nr]); /* min */ - results[1] = LM93_FAN_FROM_REG(data->block5[nr]); /* val */ - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - data->block8[nr] = LM93_FAN_TO_REG(results[0]); - lm93_write_word(client, LM93_REG_FAN_MIN(nr), - data->block8[nr]); - up(&data->update_lock); - } - } -} - -void lm93_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_VID1; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_VID_FROM_REG(data->vid[nr]); - *nrels_mag = 1; - } -} - /* some tedious bit-twiddling here to deal with the register format: data->sf_tach_to_pwm: (tach to pwm mapping bits) @@ -1838,50 +1673,8 @@ void lm93_vid(struct i2c_client *client, int operation, int ctl_name, T4 T3 T2 T1 */ -/* helper function - must grab data->update_lock before calling - fan is 0-3, indicating fan1-fan4 */ -static void lm93_write_fan_smart_tach(struct i2c_client *client, - struct lm93_data *data, int fan, long value) -{ - /* insert the new mapping and write it out */ - data->sf_tach_to_pwm = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM); - data->sf_tach_to_pwm &= ~0x3 << fan * 2; - data->sf_tach_to_pwm |= value << fan * 2; - lm93_write_byte(client, LM93_REG_SF_TACH_TO_PWM, data->sf_tach_to_pwm); - - /* insert the enable bit and write it out */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - if (value) - data->sfc2 |= 1 << fan; - else - data->sfc2 &= ~1 << fan; - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); -} - -/* helper function - must grab data->update_lock before calling - pwm is 0-1, indicating pwm1-pwm2 - this disables smart tach for all tach channels bound to the given pwm */ -static void lm93_disable_fan_smart_tach(struct i2c_client *client, - struct lm93_data *data, int pwm) -{ - int mapping = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM); - int mask; - - /* collapse the mapping into a mask of enable bits */ - mapping = (mapping >> pwm) & 0x55; - mask = mapping & 0x01; - mask |= (mapping & 0x04) >> 1; - mask |= (mapping & 0x10) >> 2; - mask |= (mapping & 0x40) >> 3; - - /* disable smart tach according to the mask */ - data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); - data->sfc2 &= ~mask; - lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); -} - -void lm93_fan_smart_tach(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) +static void lm93_fan_smart_tach(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; int nr = ctl_name - LM93_SYSCTL_FAN1_SMART_TACH; @@ -1929,36 +1722,8 @@ void lm93_fan_smart_tach(struct i2c_client *client, int operation, int ctl_name, } } -void lm93_prochot(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PROCHOT1; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = data->prochot_max[nr]; - results[1] = data->block4[nr].avg; - results[2] = data->block4[nr].avg; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - if (*nrels_mag >= 1) { - data->prochot_max[nr] = LM93_PROCHOT_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_PROCHOT_MAX(nr), - data->prochot_max[nr]); - } - up(&data->update_lock); - } -} - -void lm93_prochot_short(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) +static void lm93_prochot_short(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; @@ -1984,90 +1749,10 @@ void lm93_prochot_short(struct i2c_client *client, int operation, int ctl_name, } } -void lm93_prochot_override(struct i2c_client *client, int operation, +static void lm93_vrdhot(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_PROCHOT_OVERRIDE) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = (data->prochot_override & 0x80) ? 1 : 0; - results[1] = (data->prochot_override & 0x40) ? 1 : 0; - results[2] = data->prochot_override & 0x0f; - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - - /* grab old values */ - int force2 = (data->prochot_override & 0x40) ? 1 : 0; - int prochot = data->prochot_override & 0x0f; - - down(&data->update_lock); - if (*nrels_mag >= 3) { - data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( - results[0], results[1], results[2]); - } - if (*nrels_mag == 2) { - data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( - results[0], results[1], prochot); - } - if (*nrels_mag == 1) { - data->prochot_override = LM93_PROCHOT_OVERRIDE_TO_REG( - results[0], force2, prochot); - } - if (*nrels_mag >= 1) { - lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE, - data->prochot_override); - } - up(&data->update_lock); - } -} - -void lm93_prochot_interval(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_PROCHOT_INTERVAL) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_INTERVAL_FROM_REG( - data->prochot_interval & 0x0f); - results[1] = LM93_INTERVAL_FROM_REG( - (data->prochot_interval & 0xf0) >> 4); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - down(&data->update_lock); - data->prochot_interval = lm93_read_byte(client, - LM93_REG_PROCHOT_INTERVAL); - if (*nrels_mag >= 2) { - data->prochot_interval = - (LM93_INTERVAL_TO_REG(results[1]) << 4) | - (data->prochot_interval & 0x0f); - } - if (*nrels_mag >= 1) { - data->prochot_interval = - (data->prochot_interval & 0xf0) | - LM93_INTERVAL_TO_REG(results[0]); - lm93_write_byte(client, LM93_REG_PROCHOT_INTERVAL, - data->prochot_interval); - } - up(&data->update_lock); - } -} - -void lm93_vrdhot(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; int nr = ctl_name - LM93_SYSCTL_VRDHOT1; if (0 > nr || nr > 1) @@ -2082,116 +1767,8 @@ void lm93_vrdhot(struct i2c_client *client, int operation, int ctl_name, } } -void lm93_gpio(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - - if (ctl_name != LM93_SYSCTL_GPIO) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_GPI_FROM_REG(data->gpi); - *nrels_mag = 1; - } -} - -void lm93_pwm(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1; - u8 ctl2, ctl4; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - ctl2 = data->block9[nr][LM93_PWM_CTL2]; - ctl4 = data->block9[nr][LM93_PWM_CTL4]; - results[1] = (ctl2 & 0x01) ? 1 : 0; - ctl2 = ctl2 >> 4 & 0x0f; - if (results[1]) /* show user commanded value if enabled */ - results[0] = data->pwm_override[nr]; - else /* show present h/w value if manual pwm disabled */ - results[0] = LM93_PWM_FROM_REG(ctl2, (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); - *nrels_mag = 2; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - ctl2 = lm93_read_byte( - client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2)); - ctl4 = lm93_read_byte( - client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); - ctl2 = (ctl2 & 0x0f) | - LM93_PWM_TO_REG(results[0], (ctl4 & 0x07) ? - LM93_PWM_MAP_LO_FREQ : - LM93_PWM_MAP_HI_FREQ) << 4; - if (*nrels_mag >= 2) { - if (results[1]) - ctl2 |= 0x01; - else - ctl2 &= ~0x01; - } - /* save user commanded value */ - data->pwm_override[nr] = - LM93_PWM_FROM_REG(ctl2 >> 4 & 0x0f, - (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : - LM93_PWM_MAP_HI_FREQ); - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2), ctl2); - up(&data->update_lock); - } - } -} - -void lm93_pwm_freq(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm93_data *data = client->data; - int nr = ctl_name - LM93_SYSCTL_PWM1_FREQ; - u8 ctl4; - - if (0 > nr || nr > 1) - return; /* ERROR */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - ctl4 = data->block9[nr][LM93_PWM_CTL4]; - results[0] = LM93_PWM_FREQ_FROM_REG(ctl4); - *nrels_mag = 1; - } - else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - down(&data->update_lock); - ctl4 = lm93_read_byte( client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4)); - ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(results[0]); - data->block9[nr][LM93_PWM_CTL4] = ctl4; - - /* ctl4 == 0 -> 22.5KHz -> disable smart tach */ - if (!ctl4) - lm93_disable_fan_smart_tach(client, data, nr); - - lm93_write_byte(client, - LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4), ctl4); - up(&data->update_lock); - } - } -} - -void lm93_pwm_auto_chan(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) +static void lm93_pwm_auto_chan(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; int nr = ctl_name - LM93_SYSCTL_PWM1_AUTO_CHANNELS; @@ -2219,7 +1796,7 @@ void lm93_pwm_auto_chan(struct i2c_client *client, int operation, int ctl_name, } } -void lm93_pwm_auto_spinup_min(struct i2c_client *client, int operation, +static void lm93_pwm_auto_spinup_min(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; @@ -2227,10 +1804,10 @@ void lm93_pwm_auto_spinup_min(struct i2c_client *client, int operation, u8 ctl3, ctl4; if (0 > nr || nr > 1) - return; /* ERROR */ - + return; /* ERROR */ + if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; + *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { lm93_update_client(client); ctl3 = data->block9[nr][LM93_PWM_CTL3]; @@ -2281,17 +1858,17 @@ static u8 LM93_SPINUP_TIME_TO_REG(int time) return (u8)i; } -void lm93_pwm_auto_spinup_time(struct i2c_client *client, int operation, +static void lm93_pwm_auto_spinup_time(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; int nr = ctl_name - LM93_SYSCTL_PWM1_AUTO_SPINUP_TIME; if (0 > nr || nr > 1) - return; /* ERROR */ - + return; /* ERROR */ + if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; + *nrels_mag = 2; else if (operation == SENSORS_PROC_REAL_READ) { lm93_update_client(client); results[0] = LM93_SPINUP_TIME_FROM_REG( @@ -2330,17 +1907,17 @@ static int LM93_RAMP_FROM_REG(u8 reg) return (reg & 0x0f) * 5; } -void lm93_pwm_auto_ramp(struct i2c_client *client, int operation, +static void lm93_pwm_auto_ramp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { struct lm93_data *data = client->data; if (!(ctl_name == LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP || ctl_name == LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP)) - return; /* ERROR */ - + return; /* ERROR */ + if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; + *nrels_mag = 2; else if (operation == SENSORS_PROC_REAL_READ) { lm93_update_client(client); if (ctl_name == LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP) @@ -2368,19 +1945,355 @@ void lm93_pwm_auto_ramp(struct i2c_client *client, int operation, } } -void lm93_alarms(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) +/* These files are created for each detected LM93. This is just a template; + though at first sight, you might think we could use a statically + allocated list, we need some way to get back to the parent - which + is done through one of the 'extra' fields which are initialized + when a new copy is allocated. */ + +#define LM93_SYSCTL_IN(nr) {LM93_SYSCTL_IN##nr, "in" #nr, NULL, 0, \ + 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_in} +#define LM93_SYSCTL_TEMP(nr) {LM93_SYSCTL_TEMP##nr, "temp" #nr, NULL, 0, \ + 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_temp} +#define LM93_SYSCTL_TEMP_AUTO_BASE(nr) {LM93_SYSCTL_TEMP##nr##_AUTO_BASE, \ + "temp" #nr "_auto_base", NULL, 0, 0644, NULL, &i2c_proc_real, \ + &i2c_sysctl_real, NULL, &lm93_temp_auto_base} +#define LM93_SYSCTL_TEMP_AUTO_OFFSETS(nr) {LM93_SYSCTL_TEMP##nr##_AUTO_OFFSETS,\ + "temp" #nr "_auto_offsets", NULL, 0, 0644, NULL, &i2c_proc_real, \ + &i2c_sysctl_real, NULL, &lm93_temp_auto_offsets} +#define LM93_SYSCTL_TEMP_AUTO_BOOST(nr) { LM93_SYSCTL_TEMP##nr##_AUTO_BOOST, \ + "temp" #nr "_auto_boost", NULL, 0, 0644, NULL, &i2c_proc_real, \ + &i2c_sysctl_real, NULL, &lm93_temp_auto_boost} +#define LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(nr) { \ + LM93_SYSCTL_TEMP##nr##_AUTO_BOOST_HYST, "temp" #nr "_auto_boost_hyst", \ + NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ + &lm93_temp_auto_boost_hyst} +#define LM93_SYSCTL_TEMP_AUTO_PWM_MIN(nr) { \ + LM93_SYSCTL_TEMP##nr##_AUTO_PWM_MIN, "temp" #nr "_auto_pwm_min", \ + NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ + &lm93_temp_auto_pwm_min} +#define LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(nr) { \ + LM93_SYSCTL_TEMP##nr##_AUTO_OFFSET_HYST,"temp" #nr "_auto_offset_hyst",\ + NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ + &lm93_temp_auto_offset_hyst} +#define LM93_SYSCTL_PWM(nr) {LM93_SYSCTL_PWM##nr, "pwm" #nr, NULL, 0, \ + 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_pwm} +#define LM93_SYSCTL_PWM_FREQ(nr) {LM93_SYSCTL_PWM##nr##_FREQ, \ + "pwm" #nr "_freq", NULL, 0, 0644, NULL, &i2c_proc_real, \ + &i2c_sysctl_real, NULL, &lm93_pwm_freq} +#define LM93_SYSCTL_PWM_AUTO_CHAN(nr) {LM93_SYSCTL_PWM##nr##_AUTO_CHANNELS, \ + "pwm" #nr "_auto_channels", NULL, 0, 0644, NULL, &i2c_proc_real, \ + &i2c_sysctl_real, NULL, &lm93_pwm_auto_chan} +#define LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(nr) { \ + LM93_SYSCTL_PWM##nr##_AUTO_SPINUP_MIN, "pwm" #nr "_auto_spinup_min", \ + NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ + &lm93_pwm_auto_spinup_min} +#define LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(nr) { \ + LM93_SYSCTL_PWM##nr##_AUTO_SPINUP_TIME, "pwm" #nr "_auto_spinup_time", \ + NULL, 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, \ + &lm93_pwm_auto_spinup_time} +#define LM93_SYSCTL_FAN(nr) {LM93_SYSCTL_FAN##nr, "fan" #nr, NULL, 0, \ + 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_fan} +#define LM93_SYSCTL_VID(nr) {LM93_SYSCTL_VID##nr, "vid" #nr, NULL, 0, \ + 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_vid} +#define LM93_SYSCTL_PROCHOT(nr) {LM93_SYSCTL_PROCHOT##nr, "prochot" #nr, NULL, \ + 0, 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot} +#define LM93_SYSCTL_VRDHOT(nr) {LM93_SYSCTL_VRDHOT##nr, "vrdhot" #nr, NULL, \ + 0, 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_vrdhot} +#define LM93_SYSCTL_FAN_SMART_TACH(nr) {LM93_SYSCTL_FAN##nr##_SMART_TACH, \ + "fan" #nr "_smart_tach", NULL, 0, 0644, NULL, &i2c_proc_real, \ + &i2c_sysctl_real, NULL, &lm93_fan_smart_tach} +static ctl_table lm93_dir_table_template[] = { + LM93_SYSCTL_IN(1), + LM93_SYSCTL_IN(2), + LM93_SYSCTL_IN(3), + LM93_SYSCTL_IN(4), + LM93_SYSCTL_IN(5), + LM93_SYSCTL_IN(6), + LM93_SYSCTL_IN(7), + LM93_SYSCTL_IN(8), + LM93_SYSCTL_IN(9), + LM93_SYSCTL_IN(10), + LM93_SYSCTL_IN(11), + LM93_SYSCTL_IN(12), + LM93_SYSCTL_IN(13), + LM93_SYSCTL_IN(14), + LM93_SYSCTL_IN(15), + LM93_SYSCTL_IN(16), + + LM93_SYSCTL_TEMP(1), + LM93_SYSCTL_TEMP(2), + LM93_SYSCTL_TEMP(3), + + LM93_SYSCTL_TEMP_AUTO_BASE(1), + LM93_SYSCTL_TEMP_AUTO_BASE(2), + LM93_SYSCTL_TEMP_AUTO_BASE(3), + + LM93_SYSCTL_TEMP_AUTO_OFFSETS(1), + LM93_SYSCTL_TEMP_AUTO_OFFSETS(2), + LM93_SYSCTL_TEMP_AUTO_OFFSETS(3), + + LM93_SYSCTL_TEMP_AUTO_BOOST(1), + LM93_SYSCTL_TEMP_AUTO_BOOST(2), + LM93_SYSCTL_TEMP_AUTO_BOOST(3), + + LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(1), + LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(2), + LM93_SYSCTL_TEMP_AUTO_BOOST_HYST(3), + + LM93_SYSCTL_TEMP_AUTO_PWM_MIN(1), + LM93_SYSCTL_TEMP_AUTO_PWM_MIN(2), + LM93_SYSCTL_TEMP_AUTO_PWM_MIN(3), + + LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(1), + LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(2), + LM93_SYSCTL_TEMP_AUTO_OFFSET_HYST(3), + + LM93_SYSCTL_FAN(1), + LM93_SYSCTL_FAN(2), + LM93_SYSCTL_FAN(3), + LM93_SYSCTL_FAN(4), + + LM93_SYSCTL_FAN_SMART_TACH(1), + LM93_SYSCTL_FAN_SMART_TACH(2), + LM93_SYSCTL_FAN_SMART_TACH(3), + LM93_SYSCTL_FAN_SMART_TACH(4), + + LM93_SYSCTL_PWM(1), + LM93_SYSCTL_PWM(2), + + LM93_SYSCTL_PWM_FREQ(1), + LM93_SYSCTL_PWM_FREQ(2), + + LM93_SYSCTL_PWM_AUTO_CHAN(1), + LM93_SYSCTL_PWM_AUTO_CHAN(2), + + LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(1), + LM93_SYSCTL_PWM_AUTO_SPINUP_MIN(2), + + LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(1), + LM93_SYSCTL_PWM_AUTO_SPINUP_TIME(2), + + {LM93_SYSCTL_PWM_AUTO_PROCHOT_RAMP, "pwm_auto_prochot_ramp", NULL, 0, + 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, + &lm93_pwm_auto_ramp}, + + {LM93_SYSCTL_PWM_AUTO_VRDHOT_RAMP, "pwm_auto_vrdhot_ramp", NULL, 0, + 0644, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, + &lm93_pwm_auto_ramp}, + + LM93_SYSCTL_VID(1), + LM93_SYSCTL_VID(2), + + LM93_SYSCTL_PROCHOT(1), + LM93_SYSCTL_PROCHOT(2), + + {LM93_SYSCTL_PROCHOT_SHORT, "prochot_short", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_short}, + + {LM93_SYSCTL_PROCHOT_OVERRIDE, "prochot_override", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_override}, + + {LM93_SYSCTL_PROCHOT_INTERVAL, "prochot_interval", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_prochot_interval}, + + LM93_SYSCTL_VRDHOT(1), + LM93_SYSCTL_VRDHOT(2), + + {LM93_SYSCTL_GPIO, "gpio", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &lm93_gpio}, + + {LM93_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &lm93_alarms}, + + {0} +}; + +static void lm93_init_client(struct i2c_client *client) { - struct lm93_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 0; - else if (operation == SENSORS_PROC_REAL_READ) { - lm93_update_client(client); - results[0] = LM93_ALARMS_FROM_REG(data->block1); - *nrels_mag = 1; + int i; + u8 reg = lm93_read_byte(client, LM93_REG_CONFIG); + + /* start monitoring */ + lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01); + + if (init) { + /* enable #ALERT pin */ + reg = lm93_read_byte(client, LM93_REG_CONFIG); + lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x08); + + /* enable ASF mode for BMC status registers */ + reg = lm93_read_byte(client, LM93_REG_STATUS_CONTROL); + lm93_write_byte(client, LM93_REG_STATUS_CONTROL, reg | 0x02); + + /* set sleep state to S0 */ + lm93_write_byte(client, LM93_REG_SLEEP_CONTROL, 0); } + + /* spin until ready */ + for (i=0; i<20; i++) { + mdelay(10); + if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80) + return; + } + + printk(KERN_WARNING "lm93.o: timed out waiting for sensor " + "chip to signal ready!\n"); } +/* forward declaration */ +static struct i2c_driver lm93_driver; + +/* This function is called by i2c_detect */ +static int lm93_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +{ + int err, func; + struct lm93_data *data; + struct i2c_client *client; + void (*update)(struct lm93_data *, struct i2c_client *); + + /* lm93 is SMBus only */ + if (i2c_is_isa_adapter(adapter)) { + pr_debug("lm93.o: detect failed, " + "cannot attach to legacy adapter!\n"); + err = -ENODEV; + goto ERROR0; + } + + /* choose update routine based on bus capabilities */ + func = i2c_get_functionality(adapter); + + if ( ((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) && + (!disable_block) ) { + pr_debug("lm93.o: using SMBus block data transactions\n"); + update = lm93_update_client_full; + } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) { + pr_debug("lm93.o: disabled SMBus block data transactions\n"); + update = lm93_update_client_min; + } else { + pr_debug("lm93.o: detect failed, " + "smbus byte and/or word data not supported!\n"); + err = -ENODEV; + goto ERROR0; + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access lm78_{read,write}_value. */ + + if (!(data = kmalloc(sizeof(struct lm93_data), GFP_KERNEL))) { + pr_debug("lm93.o: detect failed, kmalloc failed!\n"); + err = -ENOMEM; + goto ERROR0; + } + + client = &data->client; + client->addr = address; + init_MUTEX(&data->lock); + client->data = data; + client->adapter = adapter; + client->driver = &lm93_driver; + client->flags = 0; + + /* detection */ + if (kind < 0) { + int mfr = lm93_read_byte(client, LM93_REG_MFR_ID); + + if (mfr != 0x01) { + pr_debug("lm93.o: detect failed, " + "bad manufacturer id 0x%02x!\n", mfr); + err = -ENODEV; + goto ERROR1; + } + } + + if (kind <= 0) { + int ver = lm93_read_byte(client, LM93_REG_VER); + + if ((ver == LM93_MFR_ID) || (ver == LM93_MFR_ID_PROTOTYPE)) { + kind = lm93; + } else { + pr_debug("lm93.o: detect failed, " + "bad version id 0x%02x!\n", ver); + if (kind == 0) + pr_debug("lm93.o: " + "(ignored 'force' parameter)\n"); + err = -ENODEV; + goto ERROR1; + } + } + + /* fill in remaining client fields */ + strcpy(client->name, "LM93 chip"); + client->id = lm93_id++; + pr_debug("lm93.o: assigning ID %d to %s at %d,0x%02x\n", client->id, + client->name, i2c_adapter_id(client->adapter), client->addr); + + /* housekeeping */ + data->type = kind; + data->valid = 0; + data->update = update; + init_MUTEX(&data->update_lock); + + /* tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto ERROR1; + + /* initialize the chip */ + lm93_init_client(client); + + /* register a new directory entry with module sensors */ + if ((data->sysctl_id = i2c_register_entry(client, "lm93", + lm93_dir_table_template)) < 0) { + err = data->sysctl_id; + goto ERROR2; + } + + return 0; + +ERROR2: + i2c_detach_client(client); +ERROR1: + kfree(data); +ERROR0: + return err; +} + +/* This function is called when: + * lm93_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and lm93_driver is still present) */ +static int lm93_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, lm93_detect); +} + +static int lm93_detach_client(struct i2c_client *client) +{ + int err; + struct lm93_data *data = client->data; + + i2c_deregister_entry(data->sysctl_id); + + if ((err = i2c_detach_client(client))) { + printk (KERN_ERR "lm93.o: Client deregistration failed; " + "client not detached.\n"); + return err; + } + + return 0; +} + +static struct i2c_driver lm93_driver = { + .owner = THIS_MODULE, + .name = "LM93 sensor driver", + .id = I2C_DRIVERID_LM93, + .flags = I2C_DF_NOTIFY, + .attach_adapter = lm93_attach_adapter, + .detach_client = lm93_detach_client, +}; + static int __init lm93_init(void) { printk(KERN_INFO "lm93.o version %s (%s)\n", LM_VERSION, LM_DATE);