Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 107301
b: refs/heads/master
c: 9ebd3d8
h: refs/heads/master
i:
  107299: 2927aae
v: v3
  • Loading branch information
David Brownell authored and Mark M. Hoffman committed Aug 1, 2008
1 parent e60ee45 commit a265fc6
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 49 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 01a52397e95a8532c59506691759dba9262d6be7
refs/heads/master: 9ebd3d822efeca2e73565516a80373c76ce3fa12
7 changes: 6 additions & 1 deletion trunk/drivers/hwmon/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,12 @@ config SENSORS_LM75
- TelCom (now Microchip) TCN75
- Texas Instruments TMP100, TMP101, TMP75, TMP175, TMP275

Most of these chips will require a "force" module parameter.
This driver supports driver model based binding through board
specific I2C device tables.

It also supports the "legacy" style of driver binding. To use
that with some chips which don't replicate LM75 quirks exactly,
you may need the "force" module parameter.

This driver can also be built as a module. If so, the module
will be called lm75.
Expand Down
206 changes: 159 additions & 47 deletions trunk/drivers/hwmon/lm75.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,28 @@

/*
* This driver handles the LM75 and compatible digital temperature sensors.
* Compatibles include at least the DS75, DS1775, MCP980x, STDS75, TCN75,
* TMP100, TMP101, TMP75, TMP175, and TMP275.
* Only types which are _not_ listed in I2C_CLIENT_INSMOD_*() need to be
* listed here. We start at 9 since I2C_CLIENT_INSMOD_*() currently allow
* definition of up to 8 chip types (plus zero).
*/

enum lm75_type { /* keep sorted in alphabetical order */
ds1775 = 9,
ds75,
/* lm75 -- in I2C_CLIENT_INSMOD_1() */
lm75a,
max6625,
max6626,
mcp980x,
stds75,
tcn75,
tmp100,
tmp101,
tmp175,
tmp275,
tmp75,
};

/* Addresses scanned by legacy style driver binding */
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
Expand All @@ -54,9 +72,10 @@ static const u8 LM75_REG_TEMP[3] = {

/* Each client has this additional data */
struct lm75_data {
struct i2c_client client;
struct i2c_client *client;
struct device *hwmon_dev;
struct mutex update_lock;
u8 orig_conf;
char valid; /* !=0 if registers are valid */
unsigned long last_updated; /* In jiffies */
u16 temp[3]; /* Register values,
Expand All @@ -65,7 +84,6 @@ struct lm75_data {
2 = hyst */
};

static void lm75_init_client(struct i2c_client *client);
static int lm75_read_value(struct i2c_client *client, u8 reg);
static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value);
static struct lm75_data *lm75_update_device(struct device *dev);
Expand Down Expand Up @@ -120,16 +138,124 @@ static const struct attribute_group lm75_group = {

/*-----------------------------------------------------------------------*/

/* "New style" I2C driver binding -- following the driver model */

static int
lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct lm75_data *data;
int status;
u8 set_mask, clr_mask;
int new;

if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
return -EIO;

data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL);
if (!data)
return -ENOMEM;

i2c_set_clientdata(client, data);

data->client = client;
mutex_init(&data->update_lock);

/* Set to LM75 resolution (9 bits, 1/2 degree C) and range.
* Then tweak to be more precise when appropriate.
*/
set_mask = 0;
clr_mask = (1 << 0) /* continuous conversions */
| (1 << 6) | (1 << 5); /* 9-bit mode */

/* configure as specified */
status = lm75_read_value(client, LM75_REG_CONF);
if (status < 0) {
dev_dbg(&client->dev, "Can't read config? %d\n", status);
goto exit_free;
}
data->orig_conf = status;
new = status & ~clr_mask;
new |= set_mask;
if (status != new)
lm75_write_value(client, LM75_REG_CONF, new);
dev_dbg(&client->dev, "Config %02x\n", new);

/* Register sysfs hooks */
status = sysfs_create_group(&client->dev.kobj, &lm75_group);
if (status)
goto exit_free;

data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
status = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}

dev_info(&client->dev, "%s: sensor '%s'\n",
data->hwmon_dev->bus_id, client->name);

return 0;

exit_remove:
sysfs_remove_group(&client->dev.kobj, &lm75_group);
exit_free:
i2c_set_clientdata(client, NULL);
kfree(data);
return status;
}

static int lm75_remove(struct i2c_client *client)
{
struct lm75_data *data = i2c_get_clientdata(client);

hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm75_group);
lm75_write_value(client, LM75_REG_CONF, data->orig_conf);
i2c_set_clientdata(client, NULL);
kfree(data);
return 0;
}

static const struct i2c_device_id lm75_ids[] = {
{ "ds1775", ds1775, },
{ "ds75", ds75, },
{ "lm75", lm75, },
{ "lm75a", lm75a, },
{ "max6625", max6625, },
{ "max6626", max6626, },
{ "mcp980x", mcp980x, },
{ "stds75", stds75, },
{ "tcn75", tcn75, },
{ "tmp100", tmp100, },
{ "tmp101", tmp101, },
{ "tmp175", tmp175, },
{ "tmp275", tmp275, },
{ "tmp75", tmp75, },
{ /* LIST END */ }
};
MODULE_DEVICE_TABLE(i2c, lm75_ids);

static struct i2c_driver lm75_driver = {
.driver = {
.name = "lm75",
},
.probe = lm75_probe,
.remove = lm75_remove,
.id_table = lm75_ids,
};

/*-----------------------------------------------------------------------*/

/* "Legacy" I2C driver binding */

static struct i2c_driver lm75_driver;
static struct i2c_driver lm75_legacy_driver;

/* This function is called by i2c_probe */
static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i;
struct i2c_client *new_client;
struct lm75_data *data;
int err = 0;

if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
Expand All @@ -139,16 +265,15 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
/* OK. For now, we presume we have a valid address. We create the
client structure, even though there may be no sensor present.
But it allows us to use i2c_smbus_read_*_data() calls. */
if (!(data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL))) {
new_client = kzalloc(sizeof *new_client, GFP_KERNEL);
if (!new_client) {
err = -ENOMEM;
goto exit;
}

new_client = &data->client;
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &lm75_driver;
new_client->driver = &lm75_legacy_driver;
new_client->flags = 0;

/* Now, we do the remaining detection. There is no identification-
Expand Down Expand Up @@ -189,38 +314,26 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_free;
}

/* NOTE: we treat "force=..." and "force_lm75=..." the same. */
/* NOTE: we treat "force=..." and "force_lm75=..." the same.
* Only new-style driver binding distinguishes chip types.
*/
strlcpy(new_client->name, "lm75", I2C_NAME_SIZE);

/* Fill in the remaining client fields and put it into the global list */
data->valid = 0;
mutex_init(&data->update_lock);

/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
err = i2c_attach_client(new_client);
if (err)
goto exit_free;

/* Initialize the LM75 chip */
lm75_init_client(new_client);

/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group)))
err = lm75_probe(new_client, NULL);
if (err < 0)
goto exit_detach;

data->hwmon_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}

return 0;

exit_remove:
sysfs_remove_group(&new_client->dev.kobj, &lm75_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
kfree(data);
kfree(new_client);
exit:
return err;
}
Expand All @@ -234,17 +347,15 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter)

static int lm75_detach_client(struct i2c_client *client)
{
struct lm75_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm75_group);
lm75_remove(client);
i2c_detach_client(client);
kfree(data);
kfree(client);
return 0;
}

static struct i2c_driver lm75_driver = {
static struct i2c_driver lm75_legacy_driver = {
.driver = {
.name = "lm75",
.name = "lm75_legacy",
},
.attach_adapter = lm75_attach_adapter,
.detach_client = lm75_detach_client,
Expand Down Expand Up @@ -276,16 +387,6 @@ static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
return i2c_smbus_write_word_data(client, reg, swab16(value));
}

static void lm75_init_client(struct i2c_client *client)
{
int reg;

/* Enable if in shutdown mode */
reg = lm75_read_value(client, LM75_REG_CONF);
if (reg >= 0 && (reg & 0x01))
lm75_write_value(client, LM75_REG_CONF, reg & 0xfe);
}

static struct lm75_data *lm75_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
Expand Down Expand Up @@ -323,11 +424,22 @@ static struct lm75_data *lm75_update_device(struct device *dev)

static int __init sensors_lm75_init(void)
{
return i2c_add_driver(&lm75_driver);
int status;

status = i2c_add_driver(&lm75_driver);
if (status < 0)
return status;

status = i2c_add_driver(&lm75_legacy_driver);
if (status < 0)
i2c_del_driver(&lm75_driver);

return status;
}

static void __exit sensors_lm75_exit(void)
{
i2c_del_driver(&lm75_legacy_driver);
i2c_del_driver(&lm75_driver);
}

Expand Down

0 comments on commit a265fc6

Please sign in to comment.