static void lm87_init_client(struct i2c_client *client) { struct lm87_data *data = i2c_get_clientdata(client); if (client->dev.platform_data) { data->channel = *(u8 *)client->dev.platform_data; lm87_write_value(client, LM87_REG_CHANNEL_MODE, data->channel); } else { data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE); } data->config = lm87_read_value(client, LM87_REG_CONFIG); if (!(data->config & 0x01)) { int i; /* Limits are left uninitialized after power-up */ for (i = 1; i < 6; i++) { lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00); lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF); } for (i = 0; i < 2; i++) { lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F); lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00); lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00); lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF); } if (data->channel & CHAN_TEMP3) { lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F); lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00); } else { lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00); lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF); } } /* Make sure Start is set and INT#_Clear is clear */ if ((data->config & 0x09) != 0x01) lm87_write_value(client, LM87_REG_CONFIG, (data->config & 0x77) | 0x01); }
/* Note: we save and restore the fan minimum here, because its value is determined in part by the fan clock divider. This follows the principle of least surprise; the user doesn't expect the fan minimum to change just because the divider changed. */ static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); unsigned long min; u8 reg; mutex_lock(&data->update_lock); min = FAN_FROM_REG(data->fan_min[nr], FAN_DIV_FROM_REG(data->fan_div[nr])); switch (val) { case 1: data->fan_div[nr] = 0; break; case 2: data->fan_div[nr] = 1; break; case 4: data->fan_div[nr] = 2; break; case 8: data->fan_div[nr] = 3; break; default: mutex_unlock(&data->update_lock); return -EINVAL; } reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV); switch (nr) { case 0: reg = (reg & 0xCF) | (data->fan_div[0] << 4); break; case 1: reg = (reg & 0x3F) | (data->fan_div[1] << 6); break; } lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg); data->fan_min[nr] = FAN_TO_REG(min, val); lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; }
static struct lm87_data *lm87_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { int i, j; dev_dbg(&client->dev, "Updating data.\n"); i = (data->channel & CHAN_TEMP3) ? 1 : 0; j = (data->channel & CHAN_TEMP3) ? 5 : 6; for (; i < j; i++) { data->in[i] = lm87_read_value(client, LM87_REG_IN(i)); data->in_min[i] = lm87_read_value(client, LM87_REG_IN_MIN(i)); data->in_max[i] = lm87_read_value(client, LM87_REG_IN_MAX(i)); } for (i = 0; i < 2; i++) { if (data->channel & CHAN_NO_FAN(i)) { data->in[6+i] = lm87_read_value(client, LM87_REG_AIN(i)); data->in_max[6+i] = lm87_read_value(client, LM87_REG_AIN_MAX(i)); data->in_min[6+i] = lm87_read_value(client, LM87_REG_AIN_MIN(i)); } else { data->fan[i] = lm87_read_value(client, LM87_REG_FAN(i)); data->fan_min[i] = lm87_read_value(client, LM87_REG_FAN_MIN(i)); } } j = (data->channel & CHAN_TEMP3) ? 3 : 2; for (i = 0 ; i < j; i++) { data->temp[i] = lm87_read_value(client, LM87_REG_TEMP[i]); data->temp_high[i] = lm87_read_value(client, LM87_REG_TEMP_HIGH[i]); data->temp_low[i] = lm87_read_value(client, LM87_REG_TEMP_LOW[i]); } i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK); j = lm87_read_value(client, LM87_REG_TEMP_HW_INT); data->temp_crit_int = min(i, j); i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK); j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT); data->temp_crit_ext = min(i, j); i = lm87_read_value(client, LM87_REG_VID_FAN_DIV); data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = (i >> 6) & 0x03; data->vid = (i & 0x0F) | (lm87_read_value(client, LM87_REG_VID4) & 0x01) << 4; data->alarms = lm87_read_value(client, LM87_REG_ALARMS1) | (lm87_read_value(client, LM87_REG_ALARMS2) << 8); data->aout = lm87_read_value(client, LM87_REG_AOUT); data->last_updated = jiffies; data->valid = 1; }