/* 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. */ void adm1025_in(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { int scales[6] = { 250, 225, 330, 500, 1200, 330 }; struct adm1025_data *data = client->data; int nr = ctl_name - ADM1025_SYSCTL_IN0; if (operation == SENSORS_PROC_REAL_INFO) *nrels_mag = 2; else if (operation == SENSORS_PROC_REAL_READ) { adm1025_update_client(client); results[0] = IN_FROM_REG(data->in_min[nr], nr) * scales[nr] / 192; results[1] = IN_FROM_REG(data->in_max[nr], nr) * scales[nr] / 192; results[2] = IN_FROM_REG(data->in[nr], nr) * scales[nr] / 192; *nrels_mag = 3; } else if (operation == SENSORS_PROC_REAL_WRITE) { if (*nrels_mag >= 1) { data->in_min[nr] = IN_TO_REG((results[0] * 192) / scales[nr], nr); adm1025_write_value(client, ADM1025_REG_IN_MIN(nr), data->in_min[nr]); } if (*nrels_mag >= 2) { data->in_max[nr] = IN_TO_REG((results[1] * 192) / scales[nr], nr); adm1025_write_value(client, ADM1025_REG_IN_MAX(nr), data->in_max[nr]); } } }
void adm1025_update_client(struct i2c_client *client) { struct adm1025_data *data = client->data; u8 i; down(&data->update_lock); if ( (jiffies - data->last_updated > (data->type == adm1025 ? HZ / 2 : HZ * 2)) || (jiffies < data->last_updated) || !data->valid) { #ifdef DEBUG printk("Starting adm1025 update\n"); #endif for (i = 0; i <= 5; i++) { data->in[i] = adm1025_read_value(client, ADM1025_REG_IN(i)); data->in_min[i] = adm1025_read_value(client, ADM1025_REG_IN_MIN(i)); data->in_max[i] = adm1025_read_value(client, ADM1025_REG_IN_MAX(i)); } data->temp = adm1025_read_value(client, ADM1025_REG_TEMP); data->rtemp = adm1025_read_value(client, ADM1025_REG_RTEMP); #ifdef DEBUG printk("The temp is %2x\n",data->temp); #endif data->temp_max = adm1025_read_value(client, ADM1025_REG_TEMP_HIGH); data->temp_min = adm1025_read_value(client, ADM1025_REG_TEMP_LOW); data->rtemp_max = adm1025_read_value(client, ADM1025_REG_RTEMP_HIGH); data->rtemp_min = adm1025_read_value(client, ADM1025_REG_RTEMP_LOW); i = adm1025_read_value(client, ADM1025_REG_VID); data->vid = i & 0x0f; data->vid |= (adm1025_read_value(client, ADM1025_REG_VID4) & 0x01) << 4; data->alarms = adm1025_read_value(client, ADM1025_REG_INT1_STAT) + (adm1025_read_value(client, ADM1025_REG_INT2_STAT) << 8); data->last_updated = jiffies; data->valid = 1; } up(&data->update_lock); }
static void adm1025_init_client(struct i2c_client *client) { u8 reg; struct adm1025_data *data = i2c_get_clientdata(client); int i; data->vrm = vid_which_vrm(); /* * Set high limits * Usually we avoid setting limits on driver init, but it happens * that the ADM1025 comes with stupid default limits (all registers * set to 0). In case the chip has not gone through any limit * setting yet, we better set the high limits to the max so that * no alarm triggers. */ for (i = 0; i < 6; i++) { reg = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MAX(i)); if (reg == 0) i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(i), 0xFF); } for (i = 0; i < 2; i++) { reg = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_HIGH(i)); if (reg == 0) i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(i), 0x7F); } /* * Start the conversions */ reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); if (!(reg & 0x01)) i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG, (reg&0x7E)|0x01); }
static void adm1025_init_client(struct i2c_client *client) { u8 reg; struct adm1025_data *data = i2c_get_clientdata(client); int i; data->vrm = vid_which_vrm(); /* */ for (i = 0; i < 6; i++) { reg = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MAX(i)); if (reg == 0) i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(i), 0xFF); } for (i = 0; i < 2; i++) { reg = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_HIGH(i)); if (reg == 0) i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(i), 0x7F); } /* */ reg = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); if (!(reg & 0x01)) i2c_smbus_write_byte_data(client, ADM1025_REG_CONFIG, (reg&0x7E)|0x01); }
static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int index = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct adm1025_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->in_max[index] = IN_TO_REG(val, in_scale[index]); i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(index), data->in_max[index]); mutex_unlock(&data->update_lock); return count; }
static struct adm1025_data *adm1025_update_device(struct device *dev) { struct adm1025_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { int i; dev_dbg(&client->dev, "Updating data.\n"); for (i = 0; i < 6; i++) { data->in[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN(i)); data->in_min[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MIN(i)); data->in_max[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_IN_MAX(i)); } for (i = 0; i < 2; i++) { data->temp[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP(i)); data->temp_min[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_LOW(i)); data->temp_max[i] = i2c_smbus_read_byte_data(client, ADM1025_REG_TEMP_HIGH(i)); } data->alarms = i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS1) | (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS2) << 8); data->vid = (i2c_smbus_read_byte_data(client, ADM1025_REG_VID) & 0x0f) | ((i2c_smbus_read_byte_data(client, ADM1025_REG_VID4) & 0x01) << 4); data->last_updated = jiffies; data->valid = 1; } mutex_unlock(&data->update_lock); return data; }
static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int index = to_sensor_dev_attr(attr)->index; struct adm1025_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; long val; int err; err = kstrtol(buf, 10, &val); if (err) return err; mutex_lock(&data->update_lock); data->in_max[index] = IN_TO_REG(val, in_scale[index]); i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(index), data->in_max[index]); mutex_unlock(&data->update_lock); return count; }
/* Called when we have found a new ADM1025. It should set limits, etc. */ void adm1025_init_client(struct i2c_client *client) { struct adm1025_data *data = client->data; data->vrm = DEFAULT_VRM; /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others. This makes most other initializations unnecessary */ adm1025_write_value(client, ADM1025_REG_CONFIG, 0x80); adm1025_write_value(client, ADM1025_REG_IN_MIN(0), IN_TO_REG(ADM1025_INIT_IN_MIN_0, 0)); adm1025_write_value(client, ADM1025_REG_IN_MAX(0), IN_TO_REG(ADM1025_INIT_IN_MAX_0, 0)); adm1025_write_value(client, ADM1025_REG_IN_MIN(1), IN_TO_REG(ADM1025_INIT_IN_MIN_1, 1)); adm1025_write_value(client, ADM1025_REG_IN_MAX(1), IN_TO_REG(ADM1025_INIT_IN_MAX_1, 1)); adm1025_write_value(client, ADM1025_REG_IN_MIN(2), IN_TO_REG(ADM1025_INIT_IN_MIN_2, 2)); adm1025_write_value(client, ADM1025_REG_IN_MAX(2), IN_TO_REG(ADM1025_INIT_IN_MAX_2, 2)); adm1025_write_value(client, ADM1025_REG_IN_MIN(3), IN_TO_REG(ADM1025_INIT_IN_MIN_3, 3)); adm1025_write_value(client, ADM1025_REG_IN_MAX(3), IN_TO_REG(ADM1025_INIT_IN_MAX_3, 3)); adm1025_write_value(client, ADM1025_REG_IN_MIN(4), IN_TO_REG(ADM1025_INIT_IN_MIN_4, 4)); adm1025_write_value(client, ADM1025_REG_IN_MAX(4), IN_TO_REG(ADM1025_INIT_IN_MAX_4, 4)); adm1025_write_value(client, ADM1025_REG_IN_MIN(5), IN_TO_REG(ADM1025_INIT_IN_MIN_5, 5)); adm1025_write_value(client, ADM1025_REG_IN_MAX(5), IN_TO_REG(ADM1025_INIT_IN_MAX_5, 5)); adm1025_write_value(client, ADM1025_REG_RTEMP_HIGH, TEMP_LIMIT_TO_REG(ADM1025_INIT_RTEMP_MAX)); adm1025_write_value(client, ADM1025_REG_RTEMP_LOW, TEMP_LIMIT_TO_REG(ADM1025_INIT_RTEMP_MIN)); adm1025_write_value(client, ADM1025_REG_TEMP_HIGH, TEMP_LIMIT_TO_REG(ADM1025_INIT_TEMP_MAX)); adm1025_write_value(client, ADM1025_REG_TEMP_LOW, TEMP_LIMIT_TO_REG(ADM1025_INIT_TEMP_MIN)); /* Start monitoring */ adm1025_write_value(client, ADM1025_REG_CONFIG, 0x01); }