📄 lm90.c
字号:
/* * Real code */static int lm90_attach_adapter(struct i2c_adapter *adapter){ if (!(adapter->class & I2C_CLASS_HWMON)) return 0; return i2c_detect(adapter, &addr_data, lm90_detect);}/* * The following function does more than just detection. If detection * succeeds, it also registers the new chip. */static int lm90_detect(struct i2c_adapter *adapter, int address, int kind){ struct i2c_client *new_client; struct lm90_data *data; int err = 0; const char *name = ""; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; if (!(data = kmalloc(sizeof(struct lm90_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } memset(data, 0, sizeof(struct lm90_data)); /* The common I2C client data is placed right before the LM90-specific data. */ new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; new_client->driver = &lm90_driver; new_client->flags = 0; /* * Now we do the remaining detection. A negative kind means that * the driver was loaded with no force parameter (default), so we * must both detect and identify the chip. A zero kind means that * the driver was loaded with the force parameter, the detection * step shall be skipped. A positive kind means that the driver * was loaded with the force parameter and a given kind of chip is * requested, so both the detection and the identification steps * are skipped. */ /* Default to an LM90 if forced */ if (kind == 0) kind = lm90; if (kind < 0) { /* detection and identification */ u8 man_id, chip_id, reg_config1, reg_convrate; man_id = i2c_smbus_read_byte_data(new_client, LM90_REG_R_MAN_ID); chip_id = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CHIP_ID); reg_config1 = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CONFIG1); reg_convrate = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CONVRATE); if (man_id == 0x01) { /* National Semiconductor */ u8 reg_config2; reg_config2 = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CONFIG2); if ((reg_config1 & 0x2A) == 0x00 && (reg_config2 & 0xF8) == 0x00 && reg_convrate <= 0x09) { if (address == 0x4C && (chip_id & 0xF0) == 0x20) { /* LM90 */ kind = lm90; } else if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */ kind = lm99; } else if (address == 0x4C && (chip_id & 0xF0) == 0x10) { /* LM86 */ kind = lm86; } } } else if (man_id == 0x41) { /* Analog Devices */ if (address == 0x4C && (chip_id & 0xF0) == 0x40 /* ADM1032 */ && (reg_config1 & 0x3F) == 0x00 && reg_convrate <= 0x0A) { kind = adm1032; } } else if (man_id == 0x4D) { /* Maxim */ if (address == 0x4C && (reg_config1 & 0x1F) == 0 && reg_convrate <= 0x09) { kind = max6657; } } if (kind <= 0) { /* identification failed */ dev_info(&adapter->dev, "Unsupported chip (man_id=0x%02X, " "chip_id=0x%02X).\n", man_id, chip_id); goto exit_free; } } if (kind == lm90) { name = "lm90"; } else if (kind == adm1032) { name = "adm1032"; } else if (kind == lm99) { name = "lm99"; } else if (kind == lm86) { name = "lm86"; } else if (kind == max6657) { name = "max6657"; } /* We can fill in the remaining client fields */ strlcpy(new_client->name, name, I2C_NAME_SIZE); new_client->id = lm90_id++; data->valid = 0; init_MUTEX(&data->update_lock); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto exit_free; /* Initialize the LM90 chip */ lm90_init_client(new_client); /* Register sysfs hooks */ device_create_file(&new_client->dev, &dev_attr_temp1_input); device_create_file(&new_client->dev, &dev_attr_temp2_input); device_create_file(&new_client->dev, &dev_attr_temp1_min); device_create_file(&new_client->dev, &dev_attr_temp2_min); device_create_file(&new_client->dev, &dev_attr_temp1_max); device_create_file(&new_client->dev, &dev_attr_temp2_max); device_create_file(&new_client->dev, &dev_attr_temp1_crit); device_create_file(&new_client->dev, &dev_attr_temp2_crit); device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst); device_create_file(&new_client->dev, &dev_attr_alarms); return 0;exit_free: kfree(data);exit: return err;}static void lm90_init_client(struct i2c_client *client){ u8 config; /* * Start the conversions. */ i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, 5); /* 2 Hz */ config = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1); if (config & 0x40) i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config & 0xBF); /* run */}static int lm90_detach_client(struct i2c_client *client){ int err; if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached.\n"); return err; } kfree(i2c_get_clientdata(client)); return 0;}static struct lm90_data *lm90_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct lm90_data *data = i2c_get_clientdata(client); down(&data->update_lock); if ((jiffies - data->last_updated > HZ * 2) || (jiffies < data->last_updated) || !data->valid) { u8 oldh, newh; dev_dbg(&client->dev, "Updating lm90 data.\n"); data->temp_input1 = i2c_smbus_read_byte_data(client, LM90_REG_R_LOCAL_TEMP); data->temp_high1 = i2c_smbus_read_byte_data(client, LM90_REG_R_LOCAL_HIGH); data->temp_low1 = i2c_smbus_read_byte_data(client, LM90_REG_R_LOCAL_LOW); data->temp_crit1 = i2c_smbus_read_byte_data(client, LM90_REG_R_LOCAL_CRIT); data->temp_crit2 = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_CRIT); data->temp_hyst = i2c_smbus_read_byte_data(client, LM90_REG_R_TCRIT_HYST); /* * There is a trick here. We have to read two registers to * have the remote sensor temperature, but we have to beware * a conversion could occur inbetween the readings. The * datasheet says we should either use the one-shot * conversion register, which we don't want to do (disables * hardware monitoring) or monitor the busy bit, which is * impossible (we can't read the values and monitor that bit * at the exact same time). So the solution used here is to * read the high byte once, then the low byte, then the high * byte again. If the new high byte matches the old one, * then we have a valid reading. Else we have to read the low * byte again, and now we believe we have a correct reading. */ oldh = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH); data->temp_input2 = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPL); newh = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH); if (newh != oldh) { data->temp_input2 = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPL);#ifdef DEBUG oldh = i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_TEMPH); /* oldh is actually newer */ if (newh != oldh) dev_warn(&client->dev, "Remote temperature may be " "wrong.\n");#endif } data->temp_input2 |= (newh << 8); data->temp_high2 = (i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_HIGHH) << 8) + i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_HIGHL); data->temp_low2 = (i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_LOWH) << 8) + i2c_smbus_read_byte_data(client, LM90_REG_R_REMOTE_LOWL); data->alarms = i2c_smbus_read_byte_data(client, LM90_REG_R_STATUS); data->last_updated = jiffies; data->valid = 1; } up(&data->update_lock); return data;}static int __init sensors_lm90_init(void){ return i2c_add_driver(&lm90_driver);}static void __exit sensors_lm90_exit(void){ i2c_del_driver(&lm90_driver);}MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");MODULE_DESCRIPTION("LM90/ADM1032 driver");MODULE_LICENSE("GPL");module_init(sensors_lm90_init);module_exit(sensors_lm90_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -