/* * w83791d.c - Part of lm_sensors, Linux kernel modules for hardware * monitoring * * Copyright (C) 2006-2007 Charles Spirakis * * 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. */ /* * Supports following chips: * * Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA * w83791d 10 5 5 3 0x71 0x5ca3 yes no * * The w83791d chip appears to be part way between the 83781d and the * 83792d. Thus, this file is derived from both the w83792d.c and * w83781d.c files. * * The w83791g chip is the same as the w83791d but lead-free. */ #include #include #include #include #include #include #include #include #include #include #define NUMBER_OF_VIN 10 #define NUMBER_OF_FANIN 5 #define NUMBER_OF_TEMPIN 3 #define NUMBER_OF_PWM 5 /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; /* Insmod parameters */ static unsigned short force_subclients[4]; module_param_array(force_subclients, short, NULL, 0); MODULE_PARM_DESC(force_subclients, "List of subclient addresses: {bus, clientaddr, subclientaddr1, subclientaddr2}"); static bool reset; module_param(reset, bool, 0); MODULE_PARM_DESC(reset, "Set to one to force a hardware chip reset"); static bool init; module_param(init, bool, 0); MODULE_PARM_DESC(init, "Set to one to force extra software initialization"); /* The W83791D registers */ static const u8 W83791D_REG_IN[NUMBER_OF_VIN] = { 0x20, /* VCOREA in DataSheet */ 0x21, /* VINR0 in DataSheet */ 0x22, /* +3.3VIN in DataSheet */ 0x23, /* VDD5V in DataSheet */ 0x24, /* +12VIN in DataSheet */ 0x25, /* -12VIN in DataSheet */ 0x26, /* -5VIN in DataSheet */ 0xB0, /* 5VSB in DataSheet */ 0xB1, /* VBAT in DataSheet */ 0xB2 /* VINR1 in DataSheet */ }; static const u8 W83791D_REG_IN_MAX[NUMBER_OF_VIN] = { 0x2B, /* VCOREA High Limit in DataSheet */ 0x2D, /* VINR0 High Limit in DataSheet */ 0x2F, /* +3.3VIN High Limit in DataSheet */ 0x31, /* VDD5V High Limit in DataSheet */ 0x33, /* +12VIN High Limit in DataSheet */ 0x35, /* -12VIN High Limit in DataSheet */ 0x37, /* -5VIN High Limit in DataSheet */ 0xB4, /* 5VSB High Limit in DataSheet */ 0xB6, /* VBAT High Limit in DataSheet */ 0xB8 /* VINR1 High Limit in DataSheet */ }; static const u8 W83791D_REG_IN_MIN[NUMBER_OF_VIN] = { 0x2C, /* VCOREA Low Limit in DataSheet */ 0x2E, /* VINR0 Low Limit in DataSheet */ 0x30, /* +3.3VIN Low Limit in DataSheet */ 0x32, /* VDD5V Low Limit in DataSheet */ 0x34, /* +12VIN Low Limit in DataSheet */ 0x36, /* -12VIN Low Limit in DataSheet */ 0x38, /* -5VIN Low Limit in DataSheet */ 0xB5, /* 5VSB Low Limit in DataSheet */ 0xB7, /* VBAT Low Limit in DataSheet */ 0xB9 /* VINR1 Low Limit in DataSheet */ }; static const u8 W83791D_REG_FAN[NUMBER_OF_FANIN] = { 0x28, /* FAN 1 Count in DataSheet */ 0x29, /* FAN 2 Count in DataSheet */ 0x2A, /* FAN 3 Count in DataSheet */ 0xBA, /* FAN 4 Count in DataSheet */ 0xBB, /* FAN 5 Count in DataSheet */ }; static const u8 W83791D_REG_FAN_MIN[NUMBER_OF_FANIN] = { 0x3B, /* FAN 1 Count Low Limit in DataSheet */ 0x3C, /* FAN 2 Count Low Limit in DataSheet */ 0x3D, /* FAN 3 Count Low Limit in DataSheet */ 0xBC, /* FAN 4 Count Low Limit in DataSheet */ 0xBD, /* FAN 5 Count Low Limit in DataSheet */ }; static const u8 W83791D_REG_PWM[NUMBER_OF_PWM] = { 0x81, /* PWM 1 duty cycle register in DataSheet */ 0x83, /* PWM 2 duty cycle register in DataSheet */ 0x94, /* PWM 3 duty cycle register in DataSheet */ 0xA0, /* PWM 4 duty cycle register in DataSheet */ 0xA1, /* PWM 5 duty cycle register in DataSheet */ }; static const u8 W83791D_REG_TEMP_TARGET[3] = { 0x85, /* PWM 1 target temperature for temp 1 */ 0x86, /* PWM 2 target temperature for temp 2 */ 0x96, /* PWM 3 target temperature for temp 3 */ }; static const u8 W83791D_REG_TEMP_TOL[2] = { 0x87, /* PWM 1/2 temperature tolerance */ 0x97, /* PWM 3 temperature tolerance */ }; static const u8 W83791D_REG_FAN_CFG[2] = { 0x84, /* FAN 1/2 configuration */ 0x95, /* FAN 3 configuration */ }; static const u8 W83791D_REG_FAN_DIV[3] = { 0x47, /* contains FAN1 and FAN2 Divisor */ 0x4b, /* contains FAN3 Divisor */ 0x5C, /* contains FAN4 and FAN5 Divisor */ }; #define W83791D_REG_BANK 0x4E #define W83791D_REG_TEMP2_CONFIG 0xC2 #define W83791D_REG_TEMP3_CONFIG 0xCA static const u8 W83791D_REG_TEMP1[3] = { 0x27, /* TEMP 1 in DataSheet */ 0x39, /* TEMP 1 Over in DataSheet */ 0x3A, /* TEMP 1 Hyst in DataSheet */ }; static const u8 W83791D_REG_TEMP_ADD[2][6] = { {0xC0, /* TEMP 2 in DataSheet */ 0xC1, /* TEMP 2(0.5 deg) in DataSheet */ 0xC5, /* TEMP 2 Over High part in DataSheet */ 0xC6, /* TEMP 2 Over Low part in DataSheet */ 0xC3, /* TEMP 2 Thyst High part in DataSheet */ 0xC4}, /* TEMP 2 Thyst Low part in DataSheet */ {0xC8, /* TEMP 3 in DataSheet */ 0xC9, /* TEMP 3(0.5 deg) in DataSheet */ 0xCD, /* TEMP 3 Over High part in DataSheet */ 0xCE, /* TEMP 3 Over Low part in DataSheet */ 0xCB, /* TEMP 3 Thyst High part in DataSheet */ 0xCC} /* TEMP 3 Thyst Low part in DataSheet */ }; #define W83791D_REG_BEEP_CONFIG 0x4D static const u8 W83791D_REG_BEEP_CTRL[3] = { 0x56, /* BEEP Control Register 1 */ 0x57, /* BEEP Control Register 2 */ 0xA3, /* BEEP Control Register 3 */ }; #define W83791D_REG_GPIO 0x15 #define W83791D_REG_CONFIG 0x40 #define W83791D_REG_VID_FANDIV 0x47 #define W83791D_REG_DID_VID4 0x49 #define W83791D_REG_WCHIPID 0x58 #define W83791D_REG_CHIPMAN 0x4F #define W83791D_REG_PIN 0x4B #define W83791D_REG_I2C_SUBADDR 0x4A #define W83791D_REG_ALARM1 0xA9 /* realtime status register1 */ #define W83791D_REG_ALARM2 0xAA /* realtime status register2 */ #define W83791D_REG_ALARM3 0xAB /* realtime status register3 */ #define W83791D_REG_VBAT 0x5D #define W83791D_REG_I2C_ADDR 0x48 /* * The SMBus locks itself. The Winbond W83791D has a bank select register * (index 0x4e), but the driver only accesses registers in bank 0. Since * we don't switch banks, we don't need any special code to handle * locking access between bank switches */ static inline int w83791d_read(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); } static inline int w83791d_write(struct i2c_client *client, u8 reg, u8 value) { return i2c_smbus_write_byte_data(client, reg, value); } /* * The analog voltage inputs have 16mV LSB. Since the sysfs output is * in mV as would be measured on the chip input pin, need to just * multiply/divide by 16 to translate from/to register values. */ #define IN_TO_REG(val) (clamp_val((((val) + 8) / 16), 0, 255)) #define IN_FROM_REG(val) ((val) * 16) static u8 fan_to_reg(long rpm, int div) { if (rpm == 0) return 255; rpm = clamp_val(rpm, 1, 1000000); return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ ((val) == 255 ? 0 : \ 1350000 / ((val) * (div)))) /* for temp1 which is 8-bit resolution, LSB = 1 degree Celsius */ #define TEMP1_FROM_REG(val) ((val) * 1000) #define TEMP1_TO_REG(val) ((val) <= -128000 ? -128 : \ (val) >= 127000 ? 127 : \ (val) < 0 ? ((val) - 500) / 1000 : \ ((val) + 500) / 1000) /* * for temp2 and temp3 which are 9-bit resolution, LSB = 0.5 degree Celsius * Assumes the top 8 bits are the integral amount and the bottom 8 bits * are the fractional amount. Since we only have 0.5 degree resolution, * the bottom 7 bits will always be zero */ #define TEMP23_FROM_REG(val) ((val) / 128 * 500) #define TEMP23_TO_REG(val) (DIV_ROUND_CLOSEST(clamp_val((val), -128000, \ 127500), 500) * 128) /* for thermal cruise target temp, 7-bits, LSB = 1 degree Celsius */ #define TARGET_TEMP_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val((val), 0, 127000), \ 1000) /* for thermal cruise temp tolerance, 4-bits, LSB = 1 degree Celsius */ #define TOL_TEMP_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val((val), 0, 15000), \ 1000) #define BEEP_MASK_TO_REG(val) ((val) & 0xffffff) #define BEEP_MASK_FROM_REG(val) ((val) & 0xffffff) #define DIV_FROM_REG(val) (1 << (val)) static u8 div_to_reg(int nr, long val) { int i; /* fan divisors max out at 128 */ val = clamp_val(val, 1, 128) >> 1; for (i = 0; i < 7; i++) { if (val == 0) break; val >>= 1; } return (u8) i; } struct w83791d_data { struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ /* array of 2 pointers to subclients */ struct i2c_client *lm75[2]; /* volts */ u8 in[NUMBER_OF_VIN]; /* Register value */ u8 in_max[NUMBER_OF_VIN]; /* Register value */ u8 in_min[NUMBER_OF_VIN]; /* Register value */ /* fans */ u8 fan[NUMBER_OF_FANIN]; /* Register value */ u8 fan_min[NUMBER_OF_FANIN]; /* Register value */ u8 fan_div[NUMBER_OF_FANIN]; /* Register encoding, shifted right */ /* Temperature sensors */ s8 temp1[3]; /* current, over, thyst */ s16 temp_add[2][3]; /* fixed point value. Top 8 bits are the * integral part, bottom 8 bits are the * fractional part. We only use the top * 9 bits as the resolution is only * to the 0.5 degree C... * two sensors with three values * (cur, over, hyst) */ /* PWMs */ u8 pwm[5]; /* pwm duty cycle */ u8 pwm_enable[3]; /* pwm enable status for fan 1-3 * (fan 4-5 only support manual mode) */ u8 temp_target[3]; /* pwm 1-3 target temperature */ u8 temp_tolerance[3]; /* pwm 1-3 temperature tolerance */ /* Misc */ u32 alarms; /* realtime status register encoding,combined */ u8 beep_enable; /* Global beep enable */ u32 beep_mask; /* Mask off specific beeps */ u8 vid; /* Register encoding, combined */ u8 vrm; /* hwmon-vid */ }; static int w83791d_probe(struct i2c_client *client, const struct i2c_device_id *id); static int w83791d_detect(struct i2c_client *client, struct i2c_board_info *info); static int w83791d_remove(struct i2c_client *client); static int w83791d_read(struct i2c_client *client, u8 reg); static int w83791d_write(struct i2c_client *client, u8 reg, u8 value); static struct w83791d_data *w83791d_update_device(struct device *dev); #ifdef DEBUG static void w83791d_print_debug(struct w83791d_data *data, struct device *dev); #endif static void w83791d_init_client(struct i2c_client *client); static const struct i2c_device_id w83791d_id[] = { { "w83791d", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, w83791d_id); static struct i2c_driver w83791d_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "w83791d", }, .probe = w83791d_probe, .remove = w83791d_remove, .id_table = w83791d_id, .detect = w83791d_detect, .address_list = normal_i2c, }; /* following are the sysfs callback functions */ #define show_in_reg(reg) \ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct sensor_device_attribute *sensor_attr = \ to_sensor_dev_attr(attr); \ struct w83791d_data *data = w83791d_update_device(dev); \ int nr = sensor_attr->index; \ return sprintf(buf, "%d\n", IN_FROM_REG(data->reg[nr])); \ } show_in_reg(in); show_in_reg(in_min); show_in_reg(in_max); #define store_in_reg(REG, reg) \ static ssize_t store_in_##reg(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ struct sensor_device_attribute *sensor_attr = \ to_sensor_dev_attr(attr); \ struct i2c_client *client = to_i2c_client(dev); \ struct w83791d_data *data = i2c_get_clientdata(client); \ int nr = sensor_attr->index; \ unsigned long val; \ int err = kstrtoul(buf, 10, &val); \ if (err) \ return err; \ mutex_lock(&data->update_lock); \ data->in_##reg[nr] = IN_TO_REG(val); \ w83791d_write(client, W83791D_REG_IN_##REG[nr], data->in_##reg[nr]); \ mutex_unlock(&data->update_lock); \ \ return count; \ } store_in_reg(MIN, min); store_in_reg(MAX, max); static struct sensor_device_attribute sda_in_input[] = { SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9), }; static struct sensor_device_attribute sda_in_min[] = { SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3), SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4), SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5), SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6), SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7), SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8), SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9), }; static struct sensor_device_attribute sda_in_max[] = { SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3), SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4), SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5), SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6), SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7), SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8), SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), }; static ssize_t show_beep(struct device *dev, struct device_attribute *attr, char *buf) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct w83791d_data *data = w83791d_update_device(dev); int bitnr = sensor_attr->index; return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1); } static ssize_t store_beep(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); int bitnr = sensor_attr->index; int bytenr = bitnr / 8; unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; val = val ? 1 : 0; mutex_lock(&data->update_lock); data->beep_mask &= ~(0xff << (bytenr * 8)); data->beep_mask |= w83791d_read(client, W83791D_REG_BEEP_CTRL[bytenr]) << (bytenr * 8); data->beep_mask &= ~(1 << bitnr); data->beep_mask |= val << bitnr; w83791d_write(client, W83791D_REG_BEEP_CTRL[bytenr], (data->beep_mask >> (bytenr * 8)) & 0xff); mutex_unlock(&data->update_lock); return count; } static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct w83791d_data *data = w83791d_update_device(dev); int bitnr = sensor_attr->index; return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); } /* * Note: The bitmask for the beep enable/disable is different than * the bitmask for the alarm. */ static struct sensor_device_attribute sda_in_beep[] = { SENSOR_ATTR(in0_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 0), SENSOR_ATTR(in1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 13), SENSOR_ATTR(in2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 2), SENSOR_ATTR(in3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 3), SENSOR_ATTR(in4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 8), SENSOR_ATTR(in5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 9), SENSOR_ATTR(in6_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 10), SENSOR_ATTR(in7_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 16), SENSOR_ATTR(in8_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 17), SENSOR_ATTR(in9_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 14), }; static struct sensor_device_attribute sda_in_alarm[] = { SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0), SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1), SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2), SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3), SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8), SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9), SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10), SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19), SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20), SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 14), }; #define show_fan_reg(reg) \ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ char *buf) \ { \ struct sensor_device_attribute *sensor_attr = \ to_sensor_dev_attr(attr); \ struct w83791d_data *data = w83791d_update_device(dev); \ int nr = sensor_attr->index; \ return sprintf(buf, "%d\n", \ FAN_FROM_REG(data->reg[nr], DIV_FROM_REG(data->fan_div[nr]))); \ } show_fan_reg(fan); show_fan_reg(fan_min); static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); int nr = sensor_attr->index; unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->fan_min[nr] = fan_to_reg(val, DIV_FROM_REG(data->fan_div[nr])); w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, char *buf) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct w83791d_data *data = w83791d_update_device(dev); return sprintf(buf, "%u\n", DIV_FROM_REG(data->fan_div[nr])); } /* * Note: we save and restore the fan minimum here, because its value is * determined in part by the fan divisor. This follows the principle of * least surprise; the user doesn't expect the fan minimum to change just * because the divisor changed. */ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct i2c_client *client = to_i2c_client(dev); struct w83791d_data *data = i2c_get_clientdata(client); int nr = sensor_attr->index; unsigned long min; u8 tmp_fan_div; u8 fan_div_reg; u8 vbat_reg; int indx = 0; u8 keep_mask = 0; u8 new_shift = 0; unsigned long val; int err; err = kstrtoul(buf, 10, &val); if (err) return err; /* Save fan_min */ min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); mutex_lock(&data->update_lock); data->fan_div[nr] = div_to_reg(nr, val); switch (nr) { case 0: indx = 0; keep_mask = 0xcf; new_shift = 4; break; case 1: indx = 0; keep_mask = 0x3f; new_shift = 6; break; case 2: indx = 1; keep_mask = 0x3f; new_shift = 6; break; case 3: indx = 2; keep_mask = 0xf8; new_shift = 0; break; case 4: indx = 2; keep_mask = 0x8f; new_shift = 4; break; #ifdef DEBUG default: dev_warn(dev, "store_fan_div: Unexpected nr seen: %d\n", nr); count = -EINVAL; goto err_exit; #endif } fan_div_reg = w83791d_read(client, W83791D_REG_FAN_DIV[indx]) & keep_mask; tmp_fan_div = (data->fan_div[nr] << new_shift) & ~keep_mask; w83791d_write(client, W83791D_REG_FAN_DIV[indx], fan_div_reg | tmp_fan_div); /* Bit 2 of fans 0-2 is stored in the vbat register (bits 5-7) */ if (nr < 3) { keep_mask = ~(1 << (nr + 5)); vbat_reg = w83791d_read(client, W83791D_REG_VBAT) & keep_mask; tmp_fan_div = (data->fan_div[nr] << (3 + nr)) & ~keep_mask; w83791d_write(client, W83791D_REG_VBAT, vbat_reg | tmp_fan_div); } /* Restore fan_min */ data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr])); w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]); #ifdef DEBUG err_exit: #endif mutex_unlock(&data->update_lock); return count; } static struct sensor_device_attribute sda_fan_input[] = { SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2), SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3), SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4), }; static struct sensor_device_attribute sda_fan_min[] = { SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 0), SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 1), SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 2), SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 3), SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 4), }; static struct sensor_device_attribute sda_fan_div[] = { SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 0), SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 1), SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 2), SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 3), SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 4), }; static struct sensor_device_attribute sda_fan_beep[] = { SENSOR_ATTR(fan1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 6), SENSOR_ATTR(fan2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 7), SENSOR_ATTR(fan3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 11), SENSOR_ATTR(fan4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 21), SENSOR_ATTR(fan5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 22), }; static struct sensor_device_attribute sda_fan_alarm[] = { SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6), SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7), SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11), SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21), SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22), }; /* read/write PWMs */ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, char *buf) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct w83791d_data *data = w83791d_update_device(dev); return sprintf(buf, "%u\n", data->pwm[nr]); } static ssize_t store_pwm(struct device *dev, struct device_attribute *attr,
heat_template_version: ocata

description: >
  OpenStack controller node configured by Puppet.

parameters:
  controllerExtraConfig:
    default: {}
    description: |
      Deprecated. Use ControllerExtraConfig via parameter_defaults instead.
    type: json
  ControllerExtraConfig:
    default: {}
    description: |
      Controller specific hiera configuration data to inject into the cluster.
    type: json
  ControllerIPs:
    default: {}
    description: >
      A network mapped list of IPs to assign to Controllers in the following form:
      {
        "internal_api": ["a.b.c.d", "e.f.g.h"],
        ...
      }
    type: json
  Debug:
    default: ''
    description: Set to True to enable debugging on all services.
    type: string
  EnableLoadBalancer:
    default: true
    description: Whether to deploy a LoadBalancer on the Controller
    type: boolean
  ExtraConfig:
    default: {}
    description: |
      Additional hieradata to inject into the cluster, note that
      ControllerExtraConfig takes precedence over ExtraConfig.
    type: json
  OvercloudControlFlavor:
    description: Flavor for control nodes to request when deploying.
    default: baremetal
    type: string
    constraints:
      - custom_constraint: nova.flavor
  controllerImage:
    type: string
    default: overcloud-full
    constraints:
      - custom_constraint: glance.image
  ImageUpdatePolicy:
    default: 'REBUILD_PRESERVE_EPHEMERAL'
    description: What policy to use when reconstructing instances. REBUILD for rebuilds, REBUILD_PRESERVE_EPHEMERAL to preserve /mnt.
    type: string
  KeyName:
    default: default
    description: Name of an existing Nova key pair to enable SSH access to the instances
    type: string
    constraints:
      - custom_constraint: nova.keypair
  NeutronPublicInterface:
    default: nic1
    description: What interface to bridge onto br-ex for network nodes.
    type: string
  ServiceNetMap:
    default: {}
    description: Mapping of service_name -> network name. Typically set
                 via parameter_defaults in the resource registry.
    type: json
  EndpointMap:
    default: {}
    description: Mapping of service endpoint -> protocol. Typically set
                 via parameter_defaults in the resource registry.
    type: json
  UpdateIdentifier:
    default: ''
    type: string
    description: >
      Setting to a previously unused value during stack-update will trigger
      package update on all nodes
  Hostname:
    type: string
    default: '' # Defaults to Heat created hostname
  HostnameMap:
    type: json
    default: {}
    description: Optional mapping to override hostnames
  NetworkDeploymentActions:
    type: comma_delimited_list
    description: >
      Heat action when to apply network configuration changes
    default: ['CREATE']
  NodeIndex:
    type: number
    default: 0
  SoftwareConfigTransport:
    default: POLL_SERVER_CFN
    description: |
      How the server should receive the metadata required for software configuration.
    type: string
    constraints:
    - allowed_values: [POLL_SERVER_CFN, POLL_SERVER_HEAT, POLL_TEMP_URL, ZAQAR_MESSAGE]
  CloudDomain:
    default: 'localdomain'
    type: string
    description: >
      The DNS domain used for the hosts. This should match the dhcp_domain
      configured in the Undercloud neutron. Defaults to localdomain.
  ControllerServerMetadata:
    default: {}
    description: >
      Extra properties or metadata passed to Nova for the created nodes in
      the overcloud. It's accessible via the Nova metadata API. This option is
      role-specific and is merged with the values given to the ServerMetadata
      parameter.
    type: json
  ServerMetadata:
    default: {}
    description: >
      Extra properties or metadata passed to Nova for the created nodes in
      the overcloud. It's accessible via the Nova metadata API. This applies to
      all roles and is merged with a role-specific metadata parameter.
    type: json
  ControllerSchedulerHints:
    type: json
    description: Optional scheduler hints to pass to nova
    default: {}
  ServiceConfigSettings:
    type: json
    default: {}
  ServiceNames:
    type: comma_delimited_list
    default: []
  MonitoringSubscriptions:
    type: comma_delimited_list
    default: []
  ServiceMetadataSettings:
    type: json
    default: {}
  ConfigCommand:
    type: string
    description: Command which will be run whenever configuration data changes
    default: os-refresh-config --timeout 14400
  UpgradeInitCommand:
    type: string
    description: |
      Command or script snippet to run on all overcloud nodes to
      initialize the upgrade process. E.g. a repository switch.
    default: ''

parameter_groups:
- label: deprecated
  description: Do not use deprecated params, they will be removed.
  parameters:
  - controllerExtraConfig

resources:

  Controller:
    type: OS::TripleO::Server
    metadata:
      os-collect-config:
        command: {get_param: ConfigCommand}
    properties:
      image: {get_param: controllerImage}
      image_update_policy: {get_param: ImageUpdatePolicy}
      flavor: {get_param: OvercloudControlFlavor}
      key_name: {get_param: KeyName}
      networks:
        - network: ctlplane
      user_data_format: SOFTWARE_CONFIG
      user_data: {get_resource: UserData}
      name:
        str_replace:
            template: {get_param: Hostname}
            params: {get_param: HostnameMap}
      software_config_transport: