mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 07:01:32 +00:00
Merge branch 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
* 'i2c-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6: (44 commits) hwmon: (w83l786ng) Convert to a new-style i2c driver hwmon: (w83l785ts) Convert to a new-style i2c driver hwmon: (w83793) Convert to a new-style i2c driver hwmon: (w83792d) Convert to a new-style i2c driver hwmon: (w83791d) Convert to a new-style i2c driver hwmon: (thmc50) Convert to a new-style i2c driver hwmon: (smsc47m192) Convert to a new-style i2c driver hwmon: (max6650) Convert to a new-style i2c driver hwmon: (max1619) Convert to a new-style i2c driver hwmon: (lm93) Convert to a new-style i2c driver hwmon: (lm92) Convert to a new-style i2c driver hwmon: (lm90) Convert to a new-style i2c driver hwmon: (lm87) Convert to a new-style i2c driver hwmon: (lm83) Convert to a new-style i2c driver hwmon: (lm80) Convert to a new-style i2c driver hwmon: (lm77) Convert to a new-style i2c driver hwmon: (lm63) Convert to a new-style i2c driver hwmon: (gl520sm) Convert to a new-style i2c driver hwmon: (gl518sm) Convert to a new-style i2c driver hwmon: (fscpos) Convert to a new-style i2c driver ...
This commit is contained in:
commit
a3cf859321
@ -49,7 +49,7 @@ $ modprobe max6875 force=0,0x50
|
|||||||
|
|
||||||
The MAX6874/MAX6875 ignores address bit 0, so this driver attaches to multiple
|
The MAX6874/MAX6875 ignores address bit 0, so this driver attaches to multiple
|
||||||
addresses. For example, for address 0x50, it also reserves 0x51.
|
addresses. For example, for address 0x50, it also reserves 0x51.
|
||||||
The even-address instance is called 'max6875', the odd one is 'max6875 subclient'.
|
The even-address instance is called 'max6875', the odd one is 'dummy'.
|
||||||
|
|
||||||
|
|
||||||
Programming the chip using i2c-dev
|
Programming the chip using i2c-dev
|
||||||
|
@ -7,7 +7,7 @@ drivers/gpio/pca9539.c instead.
|
|||||||
Supported chips:
|
Supported chips:
|
||||||
* Philips PCA9539
|
* Philips PCA9539
|
||||||
Prefix: 'pca9539'
|
Prefix: 'pca9539'
|
||||||
Addresses scanned: 0x74 - 0x77
|
Addresses scanned: none
|
||||||
Datasheet:
|
Datasheet:
|
||||||
http://www.semiconductors.philips.com/acrobat/datasheets/PCA9539_2.pdf
|
http://www.semiconductors.philips.com/acrobat/datasheets/PCA9539_2.pdf
|
||||||
|
|
||||||
@ -23,6 +23,14 @@ The input sense can also be inverted.
|
|||||||
The 16 lines are split between two bytes.
|
The 16 lines are split between two bytes.
|
||||||
|
|
||||||
|
|
||||||
|
Detection
|
||||||
|
---------
|
||||||
|
|
||||||
|
The PCA9539 is difficult to detect and not commonly found in PC machines,
|
||||||
|
so you have to pass the I2C bus and address of the installed PCA9539
|
||||||
|
devices explicitly to the driver at load time via the force=... parameter.
|
||||||
|
|
||||||
|
|
||||||
Sysfs entries
|
Sysfs entries
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@ Kernel driver pcf8574
|
|||||||
Supported chips:
|
Supported chips:
|
||||||
* Philips PCF8574
|
* Philips PCF8574
|
||||||
Prefix: 'pcf8574'
|
Prefix: 'pcf8574'
|
||||||
Addresses scanned: I2C 0x20 - 0x27
|
Addresses scanned: none
|
||||||
Datasheet: Publicly available at the Philips Semiconductors website
|
Datasheet: Publicly available at the Philips Semiconductors website
|
||||||
http://www.semiconductors.philips.com/pip/PCF8574P.html
|
http://www.semiconductors.philips.com/pip/PCF8574P.html
|
||||||
|
|
||||||
* Philips PCF8574A
|
* Philips PCF8574A
|
||||||
Prefix: 'pcf8574a'
|
Prefix: 'pcf8574a'
|
||||||
Addresses scanned: I2C 0x38 - 0x3f
|
Addresses scanned: none
|
||||||
Datasheet: Publicly available at the Philips Semiconductors website
|
Datasheet: Publicly available at the Philips Semiconductors website
|
||||||
http://www.semiconductors.philips.com/pip/PCF8574P.html
|
http://www.semiconductors.philips.com/pip/PCF8574P.html
|
||||||
|
|
||||||
@ -38,12 +38,10 @@ For more informations see the datasheet.
|
|||||||
Accessing PCF8574(A) via /sys interface
|
Accessing PCF8574(A) via /sys interface
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
! Be careful !
|
|
||||||
The PCF8574(A) is plainly impossible to detect ! Stupid chip.
|
The PCF8574(A) is plainly impossible to detect ! Stupid chip.
|
||||||
So every chip with address in the interval [20..27] and [38..3f] are
|
So, you have to pass the I2C bus and address of the installed PCF857A
|
||||||
detected as PCF8574(A). If you have other chips in this address
|
and PCF8574A devices explicitly to the driver at load time via the
|
||||||
range, the workaround is to load this module after the one
|
force=... parameter.
|
||||||
for your others chips.
|
|
||||||
|
|
||||||
On detection (i.e. insmod, modprobe et al.), directories are being
|
On detection (i.e. insmod, modprobe et al.), directories are being
|
||||||
created for each detected PCF8574(A):
|
created for each detected PCF8574(A):
|
||||||
|
@ -40,12 +40,9 @@ Detection
|
|||||||
---------
|
---------
|
||||||
|
|
||||||
There is no method known to detect whether a chip on a given I2C address is
|
There is no method known to detect whether a chip on a given I2C address is
|
||||||
a PCF8575 or whether it is any other I2C device. So there are two alternatives
|
a PCF8575 or whether it is any other I2C device, so you have to pass the I2C
|
||||||
to let the driver find the installed PCF8575 devices:
|
bus and address of the installed PCF8575 devices explicitly to the driver at
|
||||||
- Load this driver after any other I2C driver for I2C devices with addresses
|
load time via the force=... parameter.
|
||||||
in the range 0x20 .. 0x27.
|
|
||||||
- Pass the I2C bus and address of the installed PCF8575 devices explicitly to
|
|
||||||
the driver at load time via the probe=... or force=... parameters.
|
|
||||||
|
|
||||||
/sys interface
|
/sys interface
|
||||||
--------------
|
--------------
|
||||||
|
@ -23,12 +23,9 @@
|
|||||||
|
|
||||||
#include "lm75.h"
|
#include "lm75.h"
|
||||||
|
|
||||||
#define DRV_VERSION "0.3"
|
#define DRV_VERSION "0.4"
|
||||||
|
|
||||||
/* Addresses to scan */
|
enum chips { ad7416, ad7417, ad7418 };
|
||||||
static const unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END };
|
|
||||||
/* Insmod parameters */
|
|
||||||
I2C_CLIENT_INSMOD_3(ad7416, ad7417, ad7418);
|
|
||||||
|
|
||||||
/* AD7418 registers */
|
/* AD7418 registers */
|
||||||
#define AD7418_REG_TEMP_IN 0x00
|
#define AD7418_REG_TEMP_IN 0x00
|
||||||
@ -46,7 +43,6 @@ static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
|
|||||||
AD7418_REG_TEMP_OS };
|
AD7418_REG_TEMP_OS };
|
||||||
|
|
||||||
struct ad7418_data {
|
struct ad7418_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct attribute_group attrs;
|
struct attribute_group attrs;
|
||||||
enum chips type;
|
enum chips type;
|
||||||
@ -58,16 +54,25 @@ struct ad7418_data {
|
|||||||
u16 in[4];
|
u16 in[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ad7418_attach_adapter(struct i2c_adapter *adapter);
|
static int ad7418_probe(struct i2c_client *client,
|
||||||
static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int ad7418_detach_client(struct i2c_client *client);
|
static int ad7418_remove(struct i2c_client *client);
|
||||||
|
|
||||||
|
static const struct i2c_device_id ad7418_id[] = {
|
||||||
|
{ "ad7416", ad7416 },
|
||||||
|
{ "ad7417", ad7417 },
|
||||||
|
{ "ad7418", ad7418 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, ad7418_id);
|
||||||
|
|
||||||
static struct i2c_driver ad7418_driver = {
|
static struct i2c_driver ad7418_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ad7418",
|
.name = "ad7418",
|
||||||
},
|
},
|
||||||
.attach_adapter = ad7418_attach_adapter,
|
.probe = ad7418_probe,
|
||||||
.detach_client = ad7418_detach_client,
|
.remove = ad7418_remove,
|
||||||
|
.id_table = ad7418_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* All registers are word-sized, except for the configuration registers.
|
/* All registers are word-sized, except for the configuration registers.
|
||||||
@ -192,13 +197,6 @@ static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 1);
|
|||||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2);
|
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2);
|
||||||
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3);
|
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3);
|
||||||
|
|
||||||
static int ad7418_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, ad7418_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct attribute *ad7416_attributes[] = {
|
static struct attribute *ad7416_attributes[] = {
|
||||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
|
||||||
@ -225,98 +223,46 @@ static struct attribute *ad7418_attributes[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
|
static int ad7418_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
struct i2c_client *client;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct ad7418_data *data;
|
struct ad7418_data *data;
|
||||||
int err = 0;
|
int err;
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||||
I2C_FUNC_SMBUS_WORD_DATA))
|
I2C_FUNC_SMBUS_WORD_DATA)) {
|
||||||
|
err = -EOPNOTSUPP;
|
||||||
goto exit;
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL))) {
|
if (!(data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL))) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &ad7418_driver;
|
|
||||||
|
|
||||||
i2c_set_clientdata(client, data);
|
i2c_set_clientdata(client, data);
|
||||||
|
|
||||||
mutex_init(&data->lock);
|
mutex_init(&data->lock);
|
||||||
|
data->type = id->driver_data;
|
||||||
/* AD7418 has a curious behaviour on registers 6 and 7. They
|
|
||||||
* both always read 0xC071 and are not documented on the datasheet.
|
|
||||||
* We use them to detect the chip.
|
|
||||||
*/
|
|
||||||
if (kind <= 0) {
|
|
||||||
int reg, reg6, reg7;
|
|
||||||
|
|
||||||
/* the AD7416 lies within this address range, but I have
|
|
||||||
* no means to check.
|
|
||||||
*/
|
|
||||||
if (address >= 0x48 && address <= 0x4f) {
|
|
||||||
/* XXX add tests for AD7416 here */
|
|
||||||
/* data->type = ad7416; */
|
|
||||||
}
|
|
||||||
/* here we might have AD7417 or AD7418 */
|
|
||||||
else if (address >= 0x28 && address <= 0x2f) {
|
|
||||||
reg6 = i2c_smbus_read_word_data(client, 0x06);
|
|
||||||
reg7 = i2c_smbus_read_word_data(client, 0x07);
|
|
||||||
|
|
||||||
if (address == 0x28 && reg6 == 0xC071 && reg7 == 0xC071)
|
|
||||||
data->type = ad7418;
|
|
||||||
|
|
||||||
/* XXX add tests for AD7417 here */
|
|
||||||
|
|
||||||
|
|
||||||
/* both AD7417 and AD7418 have bits 0-5 of
|
|
||||||
* the CONF2 register at 0
|
|
||||||
*/
|
|
||||||
reg = i2c_smbus_read_byte_data(client,
|
|
||||||
AD7418_REG_CONF2);
|
|
||||||
if (reg & 0x3F)
|
|
||||||
data->type = any_chip; /* detection failed */
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dev_dbg(&adapter->dev, "detection forced\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kind > 0)
|
|
||||||
data->type = kind;
|
|
||||||
else if (kind < 0 && data->type == any_chip) {
|
|
||||||
err = -ENODEV;
|
|
||||||
goto exit_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (data->type) {
|
switch (data->type) {
|
||||||
case any_chip:
|
|
||||||
case ad7416:
|
case ad7416:
|
||||||
data->adc_max = 0;
|
data->adc_max = 0;
|
||||||
data->attrs.attrs = ad7416_attributes;
|
data->attrs.attrs = ad7416_attributes;
|
||||||
strlcpy(client->name, "ad7416", I2C_NAME_SIZE);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ad7417:
|
case ad7417:
|
||||||
data->adc_max = 4;
|
data->adc_max = 4;
|
||||||
data->attrs.attrs = ad7417_attributes;
|
data->attrs.attrs = ad7417_attributes;
|
||||||
strlcpy(client->name, "ad7417", I2C_NAME_SIZE);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ad7418:
|
case ad7418:
|
||||||
data->adc_max = 1;
|
data->adc_max = 1;
|
||||||
data->attrs.attrs = ad7418_attributes;
|
data->attrs.attrs = ad7418_attributes;
|
||||||
strlcpy(client->name, "ad7418", I2C_NAME_SIZE);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
dev_info(&client->dev, "%s chip found\n", client->name);
|
dev_info(&client->dev, "%s chip found\n", client->name);
|
||||||
|
|
||||||
/* Initialize the AD7418 chip */
|
/* Initialize the AD7418 chip */
|
||||||
@ -324,7 +270,7 @@ static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -336,20 +282,17 @@ static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ad7418_detach_client(struct i2c_client *client)
|
static int ad7418_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct ad7418_data *data = i2c_get_clientdata(client);
|
struct ad7418_data *data = i2c_get_clientdata(client);
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||||
i2c_detach_client(client);
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,6 @@ clearing it. Weird, ey? --Phil */
|
|||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct adm1021_data {
|
struct adm1021_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
enum chips type;
|
enum chips type;
|
||||||
|
|
||||||
@ -98,23 +97,42 @@ struct adm1021_data {
|
|||||||
u8 remote_temp_offset_prec;
|
u8 remote_temp_offset_prec;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adm1021_attach_adapter(struct i2c_adapter *adapter);
|
static int adm1021_probe(struct i2c_client *client,
|
||||||
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
|
static int adm1021_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void adm1021_init_client(struct i2c_client *client);
|
static void adm1021_init_client(struct i2c_client *client);
|
||||||
static int adm1021_detach_client(struct i2c_client *client);
|
static int adm1021_remove(struct i2c_client *client);
|
||||||
static struct adm1021_data *adm1021_update_device(struct device *dev);
|
static struct adm1021_data *adm1021_update_device(struct device *dev);
|
||||||
|
|
||||||
/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
|
/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
|
||||||
static int read_only;
|
static int read_only;
|
||||||
|
|
||||||
|
|
||||||
|
static const struct i2c_device_id adm1021_id[] = {
|
||||||
|
{ "adm1021", adm1021 },
|
||||||
|
{ "adm1023", adm1023 },
|
||||||
|
{ "max1617", max1617 },
|
||||||
|
{ "max1617a", max1617a },
|
||||||
|
{ "thmc10", thmc10 },
|
||||||
|
{ "lm84", lm84 },
|
||||||
|
{ "gl523sm", gl523sm },
|
||||||
|
{ "mc1066", mc1066 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, adm1021_id);
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
/* This is the driver that will be inserted */
|
||||||
static struct i2c_driver adm1021_driver = {
|
static struct i2c_driver adm1021_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "adm1021",
|
.name = "adm1021",
|
||||||
},
|
},
|
||||||
.attach_adapter = adm1021_attach_adapter,
|
.probe = adm1021_probe,
|
||||||
.detach_client = adm1021_detach_client,
|
.remove = adm1021_remove,
|
||||||
|
.id_table = adm1021_id,
|
||||||
|
.detect = adm1021_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t show_temp(struct device *dev,
|
static ssize_t show_temp(struct device *dev,
|
||||||
@ -216,13 +234,6 @@ static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
|
|||||||
|
|
||||||
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
|
||||||
|
|
||||||
static int adm1021_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, adm1021_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct attribute *adm1021_attributes[] = {
|
static struct attribute *adm1021_attributes[] = {
|
||||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||||
@ -243,36 +254,21 @@ static const struct attribute_group adm1021_group = {
|
|||||||
.attrs = adm1021_attributes,
|
.attrs = adm1021_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int adm1021_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
int i;
|
int i;
|
||||||
struct i2c_client *client;
|
|
||||||
struct adm1021_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *type_name = "";
|
const char *type_name = "";
|
||||||
int conv_rate, status, config;
|
int conv_rate, status, config;
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
pr_debug("adm1021: detect failed, "
|
pr_debug("adm1021: detect failed, "
|
||||||
"smbus byte data not supported!\n");
|
"smbus byte data not supported!\n");
|
||||||
goto error0;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access adm1021 register values. */
|
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL))) {
|
|
||||||
pr_debug("adm1021: detect failed, kzalloc failed!\n");
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto error0;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &adm1021_driver;
|
|
||||||
status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS);
|
status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS);
|
||||||
conv_rate = i2c_smbus_read_byte_data(client,
|
conv_rate = i2c_smbus_read_byte_data(client,
|
||||||
ADM1021_REG_CONV_RATE_R);
|
ADM1021_REG_CONV_RATE_R);
|
||||||
@ -284,8 +280,7 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|| (conv_rate & 0xF8) != 0x00) {
|
|| (conv_rate & 0xF8) != 0x00) {
|
||||||
pr_debug("adm1021: detect failed, "
|
pr_debug("adm1021: detect failed, "
|
||||||
"chip not detected!\n");
|
"chip not detected!\n");
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto error1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,24 +331,36 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
type_name = "mc1066";
|
type_name = "mc1066";
|
||||||
}
|
}
|
||||||
pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
|
pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n",
|
||||||
type_name, i2c_adapter_id(adapter), address);
|
type_name, i2c_adapter_id(adapter), client->addr);
|
||||||
|
strlcpy(info->type, type_name, I2C_NAME_SIZE);
|
||||||
|
|
||||||
/* Fill in the remaining client fields */
|
return 0;
|
||||||
strlcpy(client->name, type_name, I2C_NAME_SIZE);
|
}
|
||||||
data->type = kind;
|
|
||||||
|
static int adm1021_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct adm1021_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
pr_debug("adm1021: detect failed, kzalloc failed!\n");
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto error0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
data->type = id->driver_data;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto error1;
|
|
||||||
|
|
||||||
/* Initialize the ADM1021 chip */
|
/* Initialize the ADM1021 chip */
|
||||||
if (kind != lm84 && !read_only)
|
if (data->type != lm84 && !read_only)
|
||||||
adm1021_init_client(client);
|
adm1021_init_client(client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group)))
|
||||||
goto error2;
|
goto error1;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -365,8 +372,6 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
error3:
|
error3:
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
|
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
|
||||||
error2:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
error1:
|
error1:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
error0:
|
error0:
|
||||||
@ -382,17 +387,13 @@ static void adm1021_init_client(struct i2c_client *client)
|
|||||||
i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
|
i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adm1021_detach_client(struct i2c_client *client)
|
static int adm1021_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct adm1021_data *data = i2c_get_clientdata(client);
|
struct adm1021_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
|
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* adm1025.c
|
* adm1025.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2000 Chen-Yuan Wu <gwu@esoft.com>
|
* Copyright (C) 2000 Chen-Yuan Wu <gwu@esoft.com>
|
||||||
* Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
|
* Copyright (C) 2003-2008 Jean Delvare <khali@linux-fr.org>
|
||||||
*
|
*
|
||||||
* The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6
|
* The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6
|
||||||
* voltages (including its own power source) and up to two temperatures
|
* voltages (including its own power source) and up to two temperatures
|
||||||
@ -109,22 +109,35 @@ static const int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 };
|
|||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int adm1025_attach_adapter(struct i2c_adapter *adapter);
|
static int adm1025_probe(struct i2c_client *client,
|
||||||
static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
|
static int adm1025_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void adm1025_init_client(struct i2c_client *client);
|
static void adm1025_init_client(struct i2c_client *client);
|
||||||
static int adm1025_detach_client(struct i2c_client *client);
|
static int adm1025_remove(struct i2c_client *client);
|
||||||
static struct adm1025_data *adm1025_update_device(struct device *dev);
|
static struct adm1025_data *adm1025_update_device(struct device *dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id adm1025_id[] = {
|
||||||
|
{ "adm1025", adm1025 },
|
||||||
|
{ "ne1619", ne1619 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, adm1025_id);
|
||||||
|
|
||||||
static struct i2c_driver adm1025_driver = {
|
static struct i2c_driver adm1025_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "adm1025",
|
.name = "adm1025",
|
||||||
},
|
},
|
||||||
.attach_adapter = adm1025_attach_adapter,
|
.probe = adm1025_probe,
|
||||||
.detach_client = adm1025_detach_client,
|
.remove = adm1025_remove,
|
||||||
|
.id_table = adm1025_id,
|
||||||
|
.detect = adm1025_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -132,7 +145,6 @@ static struct i2c_driver adm1025_driver = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct adm1025_data {
|
struct adm1025_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -344,13 +356,6 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int adm1025_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, adm1025_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct attribute *adm1025_attributes[] = {
|
static struct attribute *adm1025_attributes[] = {
|
||||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||||
@ -403,31 +408,16 @@ static const struct attribute_group adm1025_group_in4 = {
|
|||||||
.attrs = adm1025_attributes_in4,
|
.attrs = adm1025_attributes_in4,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
* The following function does more than just detection. If detection
|
static int adm1025_detect(struct i2c_client *client, int kind,
|
||||||
* succeeds, it also registers the new chip.
|
struct i2c_board_info *info)
|
||||||
*/
|
|
||||||
static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
{
|
||||||
struct i2c_client *client;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct adm1025_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *name = "";
|
const char *name = "";
|
||||||
u8 config;
|
u8 config;
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct adm1025_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &adm1025_driver;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we do the remaining detection. A negative kind means that
|
* Now we do the remaining detection. A negative kind means that
|
||||||
@ -448,8 +438,8 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
ADM1025_REG_STATUS2) & 0xBC) != 0x00) {
|
ADM1025_REG_STATUS2) & 0xBC) != 0x00) {
|
||||||
dev_dbg(&adapter->dev,
|
dev_dbg(&adapter->dev,
|
||||||
"ADM1025 detection failed at 0x%02x.\n",
|
"ADM1025 detection failed at 0x%02x.\n",
|
||||||
address);
|
client->addr);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,7 +455,7 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
if (man_id == 0xA1) { /* Philips */
|
if (man_id == 0xA1) { /* Philips */
|
||||||
if (address != 0x2E
|
if (client->addr != 0x2E
|
||||||
&& (chip_id & 0xF0) == 0x20) { /* NE1619 */
|
&& (chip_id & 0xF0) == 0x20) { /* NE1619 */
|
||||||
kind = ne1619;
|
kind = ne1619;
|
||||||
}
|
}
|
||||||
@ -475,7 +465,7 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
dev_info(&adapter->dev,
|
dev_info(&adapter->dev,
|
||||||
"Unsupported chip (man_id=0x%02X, "
|
"Unsupported chip (man_id=0x%02X, "
|
||||||
"chip_id=0x%02X).\n", man_id, chip_id);
|
"chip_id=0x%02X).\n", man_id, chip_id);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,23 +474,36 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
} else if (kind == ne1619) {
|
} else if (kind == ne1619) {
|
||||||
name = "ne1619";
|
name = "ne1619";
|
||||||
}
|
}
|
||||||
|
strlcpy(info->type, name, I2C_NAME_SIZE);
|
||||||
|
|
||||||
/* We can fill in the remaining client fields */
|
return 0;
|
||||||
strlcpy(client->name, name, I2C_NAME_SIZE);
|
}
|
||||||
|
|
||||||
|
static int adm1025_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct adm1025_data *data;
|
||||||
|
int err;
|
||||||
|
u8 config;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct adm1025_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Initialize the ADM1025 chip */
|
/* Initialize the ADM1025 chip */
|
||||||
adm1025_init_client(client);
|
adm1025_init_client(client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1025_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &adm1025_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
/* Pin 11 is either in4 (+12V) or VID4 */
|
/* Pin 11 is either in4 (+12V) or VID4 */
|
||||||
|
config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG);
|
||||||
if (!(config & 0x20)) {
|
if (!(config & 0x20)) {
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||||
&adm1025_group_in4)))
|
&adm1025_group_in4)))
|
||||||
@ -518,8 +521,6 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
|
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
|
sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
@ -568,18 +569,14 @@ static void adm1025_init_client(struct i2c_client *client)
|
|||||||
(reg&0x7E)|0x01);
|
(reg&0x7E)|0x01);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adm1025_detach_client(struct i2c_client *client)
|
static int adm1025_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct adm1025_data *data = i2c_get_clientdata(client);
|
struct adm1025_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
|
sysfs_remove_group(&client->dev.kobj, &adm1025_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
|
sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,6 @@ struct pwm_data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct adm1026_data {
|
struct adm1026_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
|
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
@ -293,10 +292,11 @@ struct adm1026_data {
|
|||||||
u8 config3; /* Register value */
|
u8 config3; /* Register value */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adm1026_attach_adapter(struct i2c_adapter *adapter);
|
static int adm1026_probe(struct i2c_client *client,
|
||||||
static int adm1026_detect(struct i2c_adapter *adapter, int address,
|
const struct i2c_device_id *id);
|
||||||
int kind);
|
static int adm1026_detect(struct i2c_client *client, int kind,
|
||||||
static int adm1026_detach_client(struct i2c_client *client);
|
struct i2c_board_info *info);
|
||||||
|
static int adm1026_remove(struct i2c_client *client);
|
||||||
static int adm1026_read_value(struct i2c_client *client, u8 reg);
|
static int adm1026_read_value(struct i2c_client *client, u8 reg);
|
||||||
static int adm1026_write_value(struct i2c_client *client, u8 reg, int value);
|
static int adm1026_write_value(struct i2c_client *client, u8 reg, int value);
|
||||||
static void adm1026_print_gpio(struct i2c_client *client);
|
static void adm1026_print_gpio(struct i2c_client *client);
|
||||||
@ -305,22 +305,24 @@ static struct adm1026_data *adm1026_update_device(struct device *dev);
|
|||||||
static void adm1026_init_client(struct i2c_client *client);
|
static void adm1026_init_client(struct i2c_client *client);
|
||||||
|
|
||||||
|
|
||||||
|
static const struct i2c_device_id adm1026_id[] = {
|
||||||
|
{ "adm1026", adm1026 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, adm1026_id);
|
||||||
|
|
||||||
static struct i2c_driver adm1026_driver = {
|
static struct i2c_driver adm1026_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "adm1026",
|
.name = "adm1026",
|
||||||
},
|
},
|
||||||
.attach_adapter = adm1026_attach_adapter,
|
.probe = adm1026_probe,
|
||||||
.detach_client = adm1026_detach_client,
|
.remove = adm1026_remove,
|
||||||
|
.id_table = adm1026_id,
|
||||||
|
.detect = adm1026_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adm1026_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return i2c_probe(adapter, &addr_data, adm1026_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int adm1026_read_value(struct i2c_client *client, u8 reg)
|
static int adm1026_read_value(struct i2c_client *client, u8 reg)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@ -1647,48 +1649,32 @@ static const struct attribute_group adm1026_group_in8_9 = {
|
|||||||
.attrs = adm1026_attributes_in8_9,
|
.attrs = adm1026_attributes_in8_9,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adm1026_detect(struct i2c_adapter *adapter, int address,
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
int kind)
|
static int adm1026_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
|
int address = client->addr;
|
||||||
int company, verstep;
|
int company, verstep;
|
||||||
struct i2c_client *client;
|
|
||||||
struct adm1026_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *type_name = "";
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
/* We need to be able to do byte I/O */
|
/* We need to be able to do byte I/O */
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access adm1026_{read,write}_value. */
|
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct adm1026_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &adm1026_driver;
|
|
||||||
|
|
||||||
/* Now, we do the remaining detection. */
|
/* Now, we do the remaining detection. */
|
||||||
|
|
||||||
company = adm1026_read_value(client, ADM1026_REG_COMPANY);
|
company = adm1026_read_value(client, ADM1026_REG_COMPANY);
|
||||||
verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP);
|
verstep = adm1026_read_value(client, ADM1026_REG_VERSTEP);
|
||||||
|
|
||||||
dev_dbg(&client->dev, "Detecting device at %d,0x%02x with"
|
dev_dbg(&adapter->dev, "Detecting device at %d,0x%02x with"
|
||||||
" COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
|
" COMPANY: 0x%02x and VERSTEP: 0x%02x\n",
|
||||||
i2c_adapter_id(client->adapter), client->addr,
|
i2c_adapter_id(client->adapter), client->addr,
|
||||||
company, verstep);
|
company, verstep);
|
||||||
|
|
||||||
/* If auto-detecting, Determine the chip type. */
|
/* If auto-detecting, Determine the chip type. */
|
||||||
if (kind <= 0) {
|
if (kind <= 0) {
|
||||||
dev_dbg(&client->dev, "Autodetecting device at %d,0x%02x "
|
dev_dbg(&adapter->dev, "Autodetecting device at %d,0x%02x "
|
||||||
"...\n", i2c_adapter_id(adapter), address);
|
"...\n", i2c_adapter_id(adapter), address);
|
||||||
if (company == ADM1026_COMPANY_ANALOG_DEV
|
if (company == ADM1026_COMPANY_ANALOG_DEV
|
||||||
&& verstep == ADM1026_VERSTEP_ADM1026) {
|
&& verstep == ADM1026_VERSTEP_ADM1026) {
|
||||||
@ -1704,7 +1690,7 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
|
|||||||
verstep);
|
verstep);
|
||||||
kind = any_chip;
|
kind = any_chip;
|
||||||
} else {
|
} else {
|
||||||
dev_dbg(&client->dev, ": Autodetection "
|
dev_dbg(&adapter->dev, ": Autodetection "
|
||||||
"failed\n");
|
"failed\n");
|
||||||
/* Not an ADM1026 ... */
|
/* Not an ADM1026 ... */
|
||||||
if (kind == 0) { /* User used force=x,y */
|
if (kind == 0) { /* User used force=x,y */
|
||||||
@ -1713,33 +1699,29 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
|
|||||||
"force_adm1026.\n",
|
"force_adm1026.\n",
|
||||||
i2c_adapter_id(adapter), address);
|
i2c_adapter_id(adapter), address);
|
||||||
}
|
}
|
||||||
goto exitfree;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
strlcpy(info->type, "adm1026", I2C_NAME_SIZE);
|
||||||
|
|
||||||
/* Fill in the chip specific driver values */
|
return 0;
|
||||||
switch (kind) {
|
}
|
||||||
case any_chip :
|
|
||||||
type_name = "adm1026";
|
static int adm1026_probe(struct i2c_client *client,
|
||||||
break;
|
const struct i2c_device_id *id)
|
||||||
case adm1026 :
|
{
|
||||||
type_name = "adm1026";
|
struct adm1026_data *data;
|
||||||
break;
|
int err;
|
||||||
default :
|
|
||||||
dev_err(&adapter->dev, ": Internal error, invalid "
|
data = kzalloc(sizeof(struct adm1026_data), GFP_KERNEL);
|
||||||
"kind (%d)!\n", kind);
|
if (!data) {
|
||||||
err = -EFAULT;
|
err = -ENOMEM;
|
||||||
goto exitfree;
|
goto exit;
|
||||||
}
|
}
|
||||||
strlcpy(client->name, type_name, I2C_NAME_SIZE);
|
|
||||||
|
|
||||||
/* Fill in the remaining client fields */
|
i2c_set_clientdata(client, data);
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exitfree;
|
|
||||||
|
|
||||||
/* Set the VRM version */
|
/* Set the VRM version */
|
||||||
data->vrm = vid_which_vrm();
|
data->vrm = vid_which_vrm();
|
||||||
|
|
||||||
@ -1748,7 +1730,7 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
|
|||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1026_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &adm1026_group)))
|
||||||
goto exitdetach;
|
goto exitfree;
|
||||||
if (data->config1 & CFG1_AIN8_9)
|
if (data->config1 & CFG1_AIN8_9)
|
||||||
err = sysfs_create_group(&client->dev.kobj,
|
err = sysfs_create_group(&client->dev.kobj,
|
||||||
&adm1026_group_in8_9);
|
&adm1026_group_in8_9);
|
||||||
@ -1773,15 +1755,13 @@ exitremove:
|
|||||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
|
sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
|
||||||
else
|
else
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
|
sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
|
||||||
exitdetach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exitfree:
|
exitfree:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adm1026_detach_client(struct i2c_client *client)
|
static int adm1026_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct adm1026_data *data = i2c_get_clientdata(client);
|
struct adm1026_data *data = i2c_get_clientdata(client);
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
@ -1790,7 +1770,6 @@ static int adm1026_detach_client(struct i2c_client *client)
|
|||||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
|
sysfs_remove_group(&client->dev.kobj, &adm1026_group_in8_9);
|
||||||
else
|
else
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
|
sysfs_remove_group(&client->dev.kobj, &adm1026_group_temp3);
|
||||||
i2c_detach_client(client);
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -115,9 +115,11 @@ static const u8 ADM1029_REG_FAN_DIV[] = {
|
|||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int adm1029_attach_adapter(struct i2c_adapter *adapter);
|
static int adm1029_probe(struct i2c_client *client,
|
||||||
static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int adm1029_detach_client(struct i2c_client *client);
|
static int adm1029_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int adm1029_remove(struct i2c_client *client);
|
||||||
static struct adm1029_data *adm1029_update_device(struct device *dev);
|
static struct adm1029_data *adm1029_update_device(struct device *dev);
|
||||||
static int adm1029_init_client(struct i2c_client *client);
|
static int adm1029_init_client(struct i2c_client *client);
|
||||||
|
|
||||||
@ -125,12 +127,22 @@ static int adm1029_init_client(struct i2c_client *client);
|
|||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id adm1029_id[] = {
|
||||||
|
{ "adm1029", adm1029 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, adm1029_id);
|
||||||
|
|
||||||
static struct i2c_driver adm1029_driver = {
|
static struct i2c_driver adm1029_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "adm1029",
|
.name = "adm1029",
|
||||||
},
|
},
|
||||||
.attach_adapter = adm1029_attach_adapter,
|
.probe = adm1029_probe,
|
||||||
.detach_client = adm1029_detach_client,
|
.remove = adm1029_remove,
|
||||||
|
.id_table = adm1029_id,
|
||||||
|
.detect = adm1029_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -138,7 +150,6 @@ static struct i2c_driver adm1029_driver = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct adm1029_data {
|
struct adm1029_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -284,37 +295,14 @@ static const struct attribute_group adm1029_group = {
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int adm1029_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int adm1029_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, adm1029_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following function does more than just detection. If detection
|
|
||||||
* succeeds, it also registers the new chip.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
struct adm1029_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *name = "";
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &adm1029_driver;
|
|
||||||
|
|
||||||
/* Now we do the detection and identification. A negative kind
|
/* Now we do the detection and identification. A negative kind
|
||||||
* means that the driver was loaded with no force parameter
|
* means that the driver was loaded with no force parameter
|
||||||
@ -362,32 +350,41 @@ static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
if (kind <= 0) { /* identification failed */
|
if (kind <= 0) { /* identification failed */
|
||||||
pr_debug("adm1029: Unsupported chip (man_id=0x%02X, "
|
pr_debug("adm1029: Unsupported chip (man_id=0x%02X, "
|
||||||
"chip_id=0x%02X)\n", man_id, chip_id);
|
"chip_id=0x%02X)\n", man_id, chip_id);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
strlcpy(info->type, "adm1029", I2C_NAME_SIZE);
|
||||||
|
|
||||||
if (kind == adm1029) {
|
return 0;
|
||||||
name = "adm1029";
|
}
|
||||||
|
|
||||||
|
static int adm1029_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct adm1029_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can fill in the remaining client fields */
|
i2c_set_clientdata(client, data);
|
||||||
strlcpy(client->name, name, I2C_NAME_SIZE);
|
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the ADM1029 chip
|
* Initialize the ADM1029 chip
|
||||||
* Check config register
|
* Check config register
|
||||||
*/
|
*/
|
||||||
if (adm1029_init_client(client) == 0)
|
if (adm1029_init_client(client) == 0) {
|
||||||
goto exit_detach;
|
err = -ENODEV;
|
||||||
|
goto exit_free;
|
||||||
|
}
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -399,8 +396,6 @@ static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
|
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
@ -424,17 +419,13 @@ static int adm1029_init_client(struct i2c_client *client)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adm1029_detach_client(struct i2c_client *client)
|
static int adm1029_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct adm1029_data *data = i2c_get_clientdata(client);
|
struct adm1029_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
|
sysfs_remove_group(&client->dev.kobj, &adm1029_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,6 @@ typedef u8 auto_chan_table_t[8][2];
|
|||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct adm1031_data {
|
struct adm1031_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
int chip_type;
|
int chip_type;
|
||||||
@ -99,19 +98,32 @@ struct adm1031_data {
|
|||||||
s8 temp_crit[3];
|
s8 temp_crit[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adm1031_attach_adapter(struct i2c_adapter *adapter);
|
static int adm1031_probe(struct i2c_client *client,
|
||||||
static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
|
static int adm1031_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void adm1031_init_client(struct i2c_client *client);
|
static void adm1031_init_client(struct i2c_client *client);
|
||||||
static int adm1031_detach_client(struct i2c_client *client);
|
static int adm1031_remove(struct i2c_client *client);
|
||||||
static struct adm1031_data *adm1031_update_device(struct device *dev);
|
static struct adm1031_data *adm1031_update_device(struct device *dev);
|
||||||
|
|
||||||
|
static const struct i2c_device_id adm1031_id[] = {
|
||||||
|
{ "adm1030", adm1030 },
|
||||||
|
{ "adm1031", adm1031 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, adm1031_id);
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
/* This is the driver that will be inserted */
|
||||||
static struct i2c_driver adm1031_driver = {
|
static struct i2c_driver adm1031_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "adm1031",
|
.name = "adm1031",
|
||||||
},
|
},
|
||||||
.attach_adapter = adm1031_attach_adapter,
|
.probe = adm1031_probe,
|
||||||
.detach_client = adm1031_detach_client,
|
.remove = adm1031_remove,
|
||||||
|
.id_table = adm1031_id,
|
||||||
|
.detect = adm1031_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg)
|
static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg)
|
||||||
@ -693,13 +705,6 @@ static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 12);
|
|||||||
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13);
|
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 13);
|
||||||
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
|
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 14);
|
||||||
|
|
||||||
static int adm1031_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, adm1031_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct attribute *adm1031_attributes[] = {
|
static struct attribute *adm1031_attributes[] = {
|
||||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_fan1_div.dev_attr.attr,
|
&sensor_dev_attr_fan1_div.dev_attr.attr,
|
||||||
@ -770,27 +775,15 @@ static const struct attribute_group adm1031_group_opt = {
|
|||||||
.attrs = adm1031_attributes_opt,
|
.attrs = adm1031_attributes_opt,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
|
static int adm1031_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct i2c_client *client;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct adm1031_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *name = "";
|
const char *name = "";
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct adm1031_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &adm1031_driver;
|
|
||||||
|
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
int id, co;
|
int id, co;
|
||||||
@ -798,7 +791,7 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
co = i2c_smbus_read_byte_data(client, 0x3e);
|
co = i2c_smbus_read_byte_data(client, 0x3e);
|
||||||
|
|
||||||
if (!((id == 0x31 || id == 0x30) && co == 0x41))
|
if (!((id == 0x31 || id == 0x30) && co == 0x41))
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
kind = (id == 0x30) ? adm1030 : adm1031;
|
kind = (id == 0x30) ? adm1030 : adm1031;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,28 +802,43 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
* auto fan control helper table. */
|
* auto fan control helper table. */
|
||||||
if (kind == adm1030) {
|
if (kind == adm1030) {
|
||||||
name = "adm1030";
|
name = "adm1030";
|
||||||
data->chan_select_table = &auto_channel_select_table_adm1030;
|
|
||||||
} else if (kind == adm1031) {
|
} else if (kind == adm1031) {
|
||||||
name = "adm1031";
|
name = "adm1031";
|
||||||
data->chan_select_table = &auto_channel_select_table_adm1031;
|
|
||||||
}
|
}
|
||||||
data->chip_type = kind;
|
strlcpy(info->type, name, I2C_NAME_SIZE);
|
||||||
|
|
||||||
strlcpy(client->name, name, I2C_NAME_SIZE);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adm1031_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct adm1031_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct adm1031_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
data->chip_type = id->driver_data;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
if (data->chip_type == adm1030)
|
||||||
if ((err = i2c_attach_client(client)))
|
data->chan_select_table = &auto_channel_select_table_adm1030;
|
||||||
goto exit_free;
|
else
|
||||||
|
data->chan_select_table = &auto_channel_select_table_adm1031;
|
||||||
|
|
||||||
/* Initialize the ADM1031 chip */
|
/* Initialize the ADM1031 chip */
|
||||||
adm1031_init_client(client);
|
adm1031_init_client(client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &adm1031_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
if (kind == adm1031) {
|
if (data->chip_type == adm1031) {
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||||
&adm1031_group_opt)))
|
&adm1031_group_opt)))
|
||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
@ -847,25 +855,19 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
|
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
|
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adm1031_detach_client(struct i2c_client *client)
|
static int adm1031_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct adm1031_data *data = i2c_get_clientdata(client);
|
struct adm1031_data *data = i2c_get_clientdata(client);
|
||||||
int ret;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
|
sysfs_remove_group(&client->dev.kobj, &adm1031_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
|
sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
|
||||||
if ((ret = i2c_detach_client(client)) != 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -130,25 +130,37 @@ static inline unsigned int AOUT_FROM_REG(u8 reg)
|
|||||||
return SCALE(reg, 1250, 255);
|
return SCALE(reg, 1250, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adm9240_attach_adapter(struct i2c_adapter *adapter);
|
static int adm9240_probe(struct i2c_client *client,
|
||||||
static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
|
static int adm9240_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void adm9240_init_client(struct i2c_client *client);
|
static void adm9240_init_client(struct i2c_client *client);
|
||||||
static int adm9240_detach_client(struct i2c_client *client);
|
static int adm9240_remove(struct i2c_client *client);
|
||||||
static struct adm9240_data *adm9240_update_device(struct device *dev);
|
static struct adm9240_data *adm9240_update_device(struct device *dev);
|
||||||
|
|
||||||
/* driver data */
|
/* driver data */
|
||||||
|
static const struct i2c_device_id adm9240_id[] = {
|
||||||
|
{ "adm9240", adm9240 },
|
||||||
|
{ "ds1780", ds1780 },
|
||||||
|
{ "lm81", lm81 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, adm9240_id);
|
||||||
|
|
||||||
static struct i2c_driver adm9240_driver = {
|
static struct i2c_driver adm9240_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "adm9240",
|
.name = "adm9240",
|
||||||
},
|
},
|
||||||
.attach_adapter = adm9240_attach_adapter,
|
.probe = adm9240_probe,
|
||||||
.detach_client = adm9240_detach_client,
|
.remove = adm9240_remove,
|
||||||
|
.id_table = adm9240_id,
|
||||||
|
.detect = adm9240_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* per client data */
|
/* per client data */
|
||||||
struct adm9240_data {
|
struct adm9240_data {
|
||||||
enum chips type;
|
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid;
|
char valid;
|
||||||
@ -532,28 +544,17 @@ static const struct attribute_group adm9240_group = {
|
|||||||
|
|
||||||
/*** sensor chip detect and driver install ***/
|
/*** sensor chip detect and driver install ***/
|
||||||
|
|
||||||
static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int adm9240_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct i2c_client *new_client;
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
struct adm9240_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *name = "";
|
const char *name = "";
|
||||||
|
int address = new_client->addr;
|
||||||
u8 man_id, die_rev;
|
u8 man_id, die_rev;
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
|
|
||||||
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 = &adm9240_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
if (kind == 0) {
|
if (kind == 0) {
|
||||||
kind = adm9240;
|
kind = adm9240;
|
||||||
@ -566,7 +567,7 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
!= address) {
|
!= address) {
|
||||||
dev_err(&adapter->dev, "detect fail: address match, "
|
dev_err(&adapter->dev, "detect fail: address match, "
|
||||||
"0x%02x\n", address);
|
"0x%02x\n", address);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check known chip manufacturer */
|
/* check known chip manufacturer */
|
||||||
@ -581,7 +582,7 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
} else {
|
} else {
|
||||||
dev_err(&adapter->dev, "detect fail: unknown manuf, "
|
dev_err(&adapter->dev, "detect fail: unknown manuf, "
|
||||||
"0x%02x\n", man_id);
|
"0x%02x\n", man_id);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* successful detect, print chip info */
|
/* successful detect, print chip info */
|
||||||
@ -600,20 +601,31 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
} else if (kind == lm81) {
|
} else if (kind == lm81) {
|
||||||
name = "lm81";
|
name = "lm81";
|
||||||
}
|
}
|
||||||
|
strlcpy(info->type, name, I2C_NAME_SIZE);
|
||||||
|
|
||||||
/* fill in the remaining client fields and attach */
|
return 0;
|
||||||
strlcpy(new_client->name, name, I2C_NAME_SIZE);
|
}
|
||||||
data->type = kind;
|
|
||||||
|
static int adm9240_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct adm9240_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(new_client, data);
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
adm9240_init_client(new_client);
|
adm9240_init_client(new_client);
|
||||||
|
|
||||||
/* populate sysfs filesystem */
|
/* populate sysfs filesystem */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
|
if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -625,32 +637,19 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &adm9240_group);
|
sysfs_remove_group(&new_client->dev.kobj, &adm9240_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adm9240_attach_adapter(struct i2c_adapter *adapter)
|
static int adm9240_remove(struct i2c_client *client)
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, adm9240_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int adm9240_detach_client(struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
struct adm9240_data *data = i2c_get_clientdata(client);
|
struct adm9240_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &adm9240_group);
|
sysfs_remove_group(&client->dev.kobj, &adm9240_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,6 @@ static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */
|
|||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct ads7828_data {
|
struct ads7828_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock; /* mutex protect updates */
|
struct mutex update_lock; /* mutex protect updates */
|
||||||
char valid; /* !=0 if following fields are valid */
|
char valid; /* !=0 if following fields are valid */
|
||||||
@ -73,7 +72,10 @@ struct ads7828_data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Function declaration - necessary due to function dependencies */
|
/* Function declaration - necessary due to function dependencies */
|
||||||
static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind);
|
static int ads7828_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int ads7828_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id);
|
||||||
|
|
||||||
/* The ADS7828 returns the 12-bit sample in two bytes,
|
/* The ADS7828 returns the 12-bit sample in two bytes,
|
||||||
these are read as a word then byte-swapped */
|
these are read as a word then byte-swapped */
|
||||||
@ -156,58 +158,43 @@ static const struct attribute_group ads7828_group = {
|
|||||||
.attrs = ads7828_attributes,
|
.attrs = ads7828_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ads7828_attach_adapter(struct i2c_adapter *adapter)
|
static int ads7828_remove(struct i2c_client *client)
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, ads7828_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ads7828_detach_client(struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
struct ads7828_data *data = i2c_get_clientdata(client);
|
struct ads7828_data *data = i2c_get_clientdata(client);
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
|
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
|
||||||
i2c_detach_client(client);
|
|
||||||
kfree(i2c_get_clientdata(client));
|
kfree(i2c_get_clientdata(client));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id ads7828_id[] = {
|
||||||
|
{ "ads7828", ads7828 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, ads7828_id);
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
/* This is the driver that will be inserted */
|
||||||
static struct i2c_driver ads7828_driver = {
|
static struct i2c_driver ads7828_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ads7828",
|
.name = "ads7828",
|
||||||
},
|
},
|
||||||
.attach_adapter = ads7828_attach_adapter,
|
.probe = ads7828_probe,
|
||||||
.detach_client = ads7828_detach_client,
|
.remove = ads7828_remove,
|
||||||
|
.id_table = ads7828_id,
|
||||||
|
.detect = ads7828_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind)
|
static int ads7828_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct i2c_client *client;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct ads7828_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *name = "";
|
|
||||||
|
|
||||||
/* Check we have a valid client */
|
/* Check we have a valid client */
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access ads7828_read_value. */
|
|
||||||
data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL);
|
|
||||||
if (!data) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &ads7828_driver;
|
|
||||||
|
|
||||||
/* Now, we do the remaining detection. There is no identification
|
/* Now, we do the remaining detection. There is no identification
|
||||||
dedicated register so attempt to sanity check using knowledge of
|
dedicated register so attempt to sanity check using knowledge of
|
||||||
@ -225,32 +212,34 @@ static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
printk(KERN_DEBUG
|
printk(KERN_DEBUG
|
||||||
"%s : Doesn't look like an ads7828 device\n",
|
"%s : Doesn't look like an ads7828 device\n",
|
||||||
__func__);
|
__func__);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
strlcpy(info->type, "ads7828", I2C_NAME_SIZE);
|
||||||
|
|
||||||
/* Determine the chip type - only one kind supported! */
|
return 0;
|
||||||
if (kind <= 0)
|
}
|
||||||
kind = ads7828;
|
|
||||||
|
|
||||||
if (kind == ads7828)
|
static int ads7828_probe(struct i2c_client *client,
|
||||||
name = "ads7828";
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct ads7828_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
/* Fill in the remaining client fields, put it into the global list */
|
data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL);
|
||||||
strlcpy(client->name, name, I2C_NAME_SIZE);
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
err = i2c_attach_client(client);
|
|
||||||
if (err)
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
|
err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
|
||||||
if (err)
|
if (err)
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -262,8 +251,6 @@ static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
|
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
|
@ -138,7 +138,6 @@ I2C_CLIENT_INSMOD_1(adt7470);
|
|||||||
#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
|
#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
|
||||||
|
|
||||||
struct adt7470_data {
|
struct adt7470_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct attribute_group attrs;
|
struct attribute_group attrs;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
@ -164,16 +163,28 @@ struct adt7470_data {
|
|||||||
u8 pwm_auto_temp[ADT7470_PWM_COUNT];
|
u8 pwm_auto_temp[ADT7470_PWM_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adt7470_attach_adapter(struct i2c_adapter *adapter);
|
static int adt7470_probe(struct i2c_client *client,
|
||||||
static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int adt7470_detach_client(struct i2c_client *client);
|
static int adt7470_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int adt7470_remove(struct i2c_client *client);
|
||||||
|
|
||||||
|
static const struct i2c_device_id adt7470_id[] = {
|
||||||
|
{ "adt7470", adt7470 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, adt7470_id);
|
||||||
|
|
||||||
static struct i2c_driver adt7470_driver = {
|
static struct i2c_driver adt7470_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "adt7470",
|
.name = "adt7470",
|
||||||
},
|
},
|
||||||
.attach_adapter = adt7470_attach_adapter,
|
.probe = adt7470_probe,
|
||||||
.detach_client = adt7470_detach_client,
|
.remove = adt7470_remove,
|
||||||
|
.id_table = adt7470_id,
|
||||||
|
.detect = adt7470_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1004,64 +1015,52 @@ static struct attribute *adt7470_attr[] =
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adt7470_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int adt7470_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, adt7470_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
struct adt7470_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &adt7470_driver;
|
|
||||||
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
|
|
||||||
mutex_init(&data->lock);
|
|
||||||
|
|
||||||
if (kind <= 0) {
|
if (kind <= 0) {
|
||||||
int vendor, device, revision;
|
int vendor, device, revision;
|
||||||
|
|
||||||
vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
|
vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR);
|
||||||
if (vendor != ADT7470_VENDOR) {
|
if (vendor != ADT7470_VENDOR)
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto exit_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
|
device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE);
|
||||||
if (device != ADT7470_DEVICE) {
|
if (device != ADT7470_DEVICE)
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto exit_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
revision = i2c_smbus_read_byte_data(client,
|
revision = i2c_smbus_read_byte_data(client,
|
||||||
ADT7470_REG_REVISION);
|
ADT7470_REG_REVISION);
|
||||||
if (revision != ADT7470_REVISION) {
|
if (revision != ADT7470_REVISION)
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto exit_free;
|
|
||||||
}
|
|
||||||
} else
|
} else
|
||||||
dev_dbg(&adapter->dev, "detection forced\n");
|
dev_dbg(&adapter->dev, "detection forced\n");
|
||||||
|
|
||||||
strlcpy(client->name, "adt7470", I2C_NAME_SIZE);
|
strlcpy(info->type, "adt7470", I2C_NAME_SIZE);
|
||||||
|
|
||||||
if ((err = i2c_attach_client(client)))
|
return 0;
|
||||||
goto exit_free;
|
}
|
||||||
|
|
||||||
|
static int adt7470_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct adt7470_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->lock);
|
||||||
|
|
||||||
dev_info(&client->dev, "%s chip found\n", client->name);
|
dev_info(&client->dev, "%s chip found\n", client->name);
|
||||||
|
|
||||||
@ -1071,7 +1070,7 @@ static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
data->attrs.attrs = adt7470_attr;
|
data->attrs.attrs = adt7470_attr;
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -1083,21 +1082,18 @@ static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adt7470_detach_client(struct i2c_client *client)
|
static int adt7470_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct adt7470_data *data = i2c_get_clientdata(client);
|
struct adt7470_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||||
i2c_detach_client(client);
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,6 @@ I2C_CLIENT_INSMOD_1(adt7473);
|
|||||||
#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
|
#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
|
||||||
|
|
||||||
struct adt7473_data {
|
struct adt7473_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct attribute_group attrs;
|
struct attribute_group attrs;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
@ -178,16 +177,28 @@ struct adt7473_data {
|
|||||||
u8 max_duty_at_overheat;
|
u8 max_duty_at_overheat;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adt7473_attach_adapter(struct i2c_adapter *adapter);
|
static int adt7473_probe(struct i2c_client *client,
|
||||||
static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int adt7473_detach_client(struct i2c_client *client);
|
static int adt7473_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int adt7473_remove(struct i2c_client *client);
|
||||||
|
|
||||||
|
static const struct i2c_device_id adt7473_id[] = {
|
||||||
|
{ "adt7473", adt7473 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, adt7473_id);
|
||||||
|
|
||||||
static struct i2c_driver adt7473_driver = {
|
static struct i2c_driver adt7473_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "adt7473",
|
.name = "adt7473",
|
||||||
},
|
},
|
||||||
.attach_adapter = adt7473_attach_adapter,
|
.probe = adt7473_probe,
|
||||||
.detach_client = adt7473_detach_client,
|
.remove = adt7473_remove,
|
||||||
|
.id_table = adt7473_id,
|
||||||
|
.detect = adt7473_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1042,21 +1053,43 @@ static struct attribute *adt7473_attr[] =
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static int adt7473_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int adt7473_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, adt7473_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
struct adt7473_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (kind <= 0) {
|
||||||
|
int vendor, device, revision;
|
||||||
|
|
||||||
|
vendor = i2c_smbus_read_byte_data(client, ADT7473_REG_VENDOR);
|
||||||
|
if (vendor != ADT7473_VENDOR)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
device = i2c_smbus_read_byte_data(client, ADT7473_REG_DEVICE);
|
||||||
|
if (device != ADT7473_DEVICE)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
revision = i2c_smbus_read_byte_data(client,
|
||||||
|
ADT7473_REG_REVISION);
|
||||||
|
if (revision != ADT7473_REV_68 && revision != ADT7473_REV_69)
|
||||||
|
return -ENODEV;
|
||||||
|
} else
|
||||||
|
dev_dbg(&adapter->dev, "detection forced\n");
|
||||||
|
|
||||||
|
strlcpy(info->type, "adt7473", I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int adt7473_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct adt7473_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
data = kzalloc(sizeof(struct adt7473_data), GFP_KERNEL);
|
data = kzalloc(sizeof(struct adt7473_data), GFP_KERNEL);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@ -1064,45 +1097,9 @@ static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &adt7473_driver;
|
|
||||||
|
|
||||||
i2c_set_clientdata(client, data);
|
i2c_set_clientdata(client, data);
|
||||||
|
|
||||||
mutex_init(&data->lock);
|
mutex_init(&data->lock);
|
||||||
|
|
||||||
if (kind <= 0) {
|
|
||||||
int vendor, device, revision;
|
|
||||||
|
|
||||||
vendor = i2c_smbus_read_byte_data(client, ADT7473_REG_VENDOR);
|
|
||||||
if (vendor != ADT7473_VENDOR) {
|
|
||||||
err = -ENODEV;
|
|
||||||
goto exit_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
device = i2c_smbus_read_byte_data(client, ADT7473_REG_DEVICE);
|
|
||||||
if (device != ADT7473_DEVICE) {
|
|
||||||
err = -ENODEV;
|
|
||||||
goto exit_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
revision = i2c_smbus_read_byte_data(client,
|
|
||||||
ADT7473_REG_REVISION);
|
|
||||||
if (revision != ADT7473_REV_68 && revision != ADT7473_REV_69) {
|
|
||||||
err = -ENODEV;
|
|
||||||
goto exit_free;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
dev_dbg(&adapter->dev, "detection forced\n");
|
|
||||||
|
|
||||||
strlcpy(client->name, "adt7473", I2C_NAME_SIZE);
|
|
||||||
|
|
||||||
err = i2c_attach_client(client);
|
|
||||||
if (err)
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
dev_info(&client->dev, "%s chip found\n", client->name);
|
dev_info(&client->dev, "%s chip found\n", client->name);
|
||||||
|
|
||||||
/* Initialize the ADT7473 chip */
|
/* Initialize the ADT7473 chip */
|
||||||
@ -1112,7 +1109,7 @@ static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
data->attrs.attrs = adt7473_attr;
|
data->attrs.attrs = adt7473_attr;
|
||||||
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
|
err = sysfs_create_group(&client->dev.kobj, &data->attrs);
|
||||||
if (err)
|
if (err)
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -1124,21 +1121,18 @@ static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adt7473_detach_client(struct i2c_client *client)
|
static int adt7473_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct adt7473_data *data = i2c_get_clientdata(client);
|
struct adt7473_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||||
i2c_detach_client(client);
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -176,10 +176,8 @@ static u8 DIV_TO_REG(long val)
|
|||||||
data is pointed to by client->data. The structure itself is
|
data is pointed to by client->data. The structure itself is
|
||||||
dynamically allocated, at the same time the client itself is allocated. */
|
dynamically allocated, at the same time the client itself is allocated. */
|
||||||
struct asb100_data {
|
struct asb100_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
enum chips type;
|
|
||||||
|
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
unsigned long last_updated; /* In jiffies */
|
unsigned long last_updated; /* In jiffies */
|
||||||
@ -206,18 +204,30 @@ struct asb100_data {
|
|||||||
static int asb100_read_value(struct i2c_client *client, u16 reg);
|
static int asb100_read_value(struct i2c_client *client, u16 reg);
|
||||||
static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val);
|
static void asb100_write_value(struct i2c_client *client, u16 reg, u16 val);
|
||||||
|
|
||||||
static int asb100_attach_adapter(struct i2c_adapter *adapter);
|
static int asb100_probe(struct i2c_client *client,
|
||||||
static int asb100_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int asb100_detach_client(struct i2c_client *client);
|
static int asb100_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int asb100_remove(struct i2c_client *client);
|
||||||
static struct asb100_data *asb100_update_device(struct device *dev);
|
static struct asb100_data *asb100_update_device(struct device *dev);
|
||||||
static void asb100_init_client(struct i2c_client *client);
|
static void asb100_init_client(struct i2c_client *client);
|
||||||
|
|
||||||
|
static const struct i2c_device_id asb100_id[] = {
|
||||||
|
{ "asb100", asb100 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, asb100_id);
|
||||||
|
|
||||||
static struct i2c_driver asb100_driver = {
|
static struct i2c_driver asb100_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "asb100",
|
.name = "asb100",
|
||||||
},
|
},
|
||||||
.attach_adapter = asb100_attach_adapter,
|
.probe = asb100_probe,
|
||||||
.detach_client = asb100_detach_client,
|
.remove = asb100_remove,
|
||||||
|
.id_table = asb100_id,
|
||||||
|
.detect = asb100_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 7 Voltages */
|
/* 7 Voltages */
|
||||||
@ -619,35 +629,13 @@ static const struct attribute_group asb100_group = {
|
|||||||
.attrs = asb100_attributes,
|
.attrs = asb100_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This function is called when:
|
static int asb100_detect_subclients(struct i2c_client *client)
|
||||||
asb100_driver is inserted (when this module is loaded), for each
|
|
||||||
available adapter
|
|
||||||
when a new adapter is inserted (and asb100_driver is still present)
|
|
||||||
*/
|
|
||||||
static int asb100_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, asb100_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
|
|
||||||
int kind, struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
int i, id, err;
|
int i, id, err;
|
||||||
|
int address = client->addr;
|
||||||
|
unsigned short sc_addr[2];
|
||||||
struct asb100_data *data = i2c_get_clientdata(client);
|
struct asb100_data *data = i2c_get_clientdata(client);
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
data->lm75[0] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
|
||||||
if (!(data->lm75[0])) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto ERROR_SC_0;
|
|
||||||
}
|
|
||||||
|
|
||||||
data->lm75[1] = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
|
||||||
if (!(data->lm75[1])) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto ERROR_SC_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
id = i2c_adapter_id(adapter);
|
id = i2c_adapter_id(adapter);
|
||||||
|
|
||||||
@ -665,37 +653,34 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
|
|||||||
asb100_write_value(client, ASB100_REG_I2C_SUBADDR,
|
asb100_write_value(client, ASB100_REG_I2C_SUBADDR,
|
||||||
(force_subclients[2] & 0x07) |
|
(force_subclients[2] & 0x07) |
|
||||||
((force_subclients[3] & 0x07) << 4));
|
((force_subclients[3] & 0x07) << 4));
|
||||||
data->lm75[0]->addr = force_subclients[2];
|
sc_addr[0] = force_subclients[2];
|
||||||
data->lm75[1]->addr = force_subclients[3];
|
sc_addr[1] = force_subclients[3];
|
||||||
} else {
|
} else {
|
||||||
int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR);
|
int val = asb100_read_value(client, ASB100_REG_I2C_SUBADDR);
|
||||||
data->lm75[0]->addr = 0x48 + (val & 0x07);
|
sc_addr[0] = 0x48 + (val & 0x07);
|
||||||
data->lm75[1]->addr = 0x48 + ((val >> 4) & 0x07);
|
sc_addr[1] = 0x48 + ((val >> 4) & 0x07);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->lm75[0]->addr == data->lm75[1]->addr) {
|
if (sc_addr[0] == sc_addr[1]) {
|
||||||
dev_err(&client->dev, "duplicate addresses 0x%x "
|
dev_err(&client->dev, "duplicate addresses 0x%x "
|
||||||
"for subclients\n", data->lm75[0]->addr);
|
"for subclients\n", sc_addr[0]);
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto ERROR_SC_2;
|
goto ERROR_SC_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i <= 1; i++) {
|
data->lm75[0] = i2c_new_dummy(adapter, sc_addr[0]);
|
||||||
i2c_set_clientdata(data->lm75[i], NULL);
|
if (!data->lm75[0]) {
|
||||||
data->lm75[i]->adapter = adapter;
|
|
||||||
data->lm75[i]->driver = &asb100_driver;
|
|
||||||
strlcpy(data->lm75[i]->name, "asb100 subclient", I2C_NAME_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = i2c_attach_client(data->lm75[0]))) {
|
|
||||||
dev_err(&client->dev, "subclient %d registration "
|
dev_err(&client->dev, "subclient %d registration "
|
||||||
"at address 0x%x failed.\n", i, data->lm75[0]->addr);
|
"at address 0x%x failed.\n", 1, sc_addr[0]);
|
||||||
|
err = -ENOMEM;
|
||||||
goto ERROR_SC_2;
|
goto ERROR_SC_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err = i2c_attach_client(data->lm75[1]))) {
|
data->lm75[1] = i2c_new_dummy(adapter, sc_addr[1]);
|
||||||
|
if (!data->lm75[1]) {
|
||||||
dev_err(&client->dev, "subclient %d registration "
|
dev_err(&client->dev, "subclient %d registration "
|
||||||
"at address 0x%x failed.\n", i, data->lm75[1]->addr);
|
"at address 0x%x failed.\n", 2, sc_addr[1]);
|
||||||
|
err = -ENOMEM;
|
||||||
goto ERROR_SC_3;
|
goto ERROR_SC_3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -703,55 +688,31 @@ static int asb100_detect_subclients(struct i2c_adapter *adapter, int address,
|
|||||||
|
|
||||||
/* Undo inits in case of errors */
|
/* Undo inits in case of errors */
|
||||||
ERROR_SC_3:
|
ERROR_SC_3:
|
||||||
i2c_detach_client(data->lm75[0]);
|
i2c_unregister_device(data->lm75[0]);
|
||||||
ERROR_SC_2:
|
ERROR_SC_2:
|
||||||
kfree(data->lm75[1]);
|
|
||||||
ERROR_SC_1:
|
|
||||||
kfree(data->lm75[0]);
|
|
||||||
ERROR_SC_0:
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int asb100_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
int err;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct i2c_client *client;
|
|
||||||
struct asb100_data *data;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
pr_debug("asb100.o: detect failed, "
|
pr_debug("asb100.o: detect failed, "
|
||||||
"smbus byte data not supported!\n");
|
"smbus byte data not supported!\n");
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto ERROR0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access asb100_{read,write}_value. */
|
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL))) {
|
|
||||||
pr_debug("asb100.o: detect failed, kzalloc failed!\n");
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto ERROR0;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
mutex_init(&data->lock);
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &asb100_driver;
|
|
||||||
|
|
||||||
/* Now, we do the remaining detection. */
|
|
||||||
|
|
||||||
/* The chip may be stuck in some other bank than bank 0. This may
|
/* The chip may be stuck in some other bank than bank 0. This may
|
||||||
make reading other information impossible. Specify a force=... or
|
make reading other information impossible. Specify a force=... or
|
||||||
force_*=... parameter, and the chip will be reset to the right
|
force_*=... parameter, and the chip will be reset to the right
|
||||||
bank. */
|
bank. */
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
|
|
||||||
int val1 = asb100_read_value(client, ASB100_REG_BANK);
|
int val1 = i2c_smbus_read_byte_data(client, ASB100_REG_BANK);
|
||||||
int val2 = asb100_read_value(client, ASB100_REG_CHIPMAN);
|
int val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
|
||||||
|
|
||||||
/* If we're in bank 0 */
|
/* If we're in bank 0 */
|
||||||
if ((!(val1 & 0x07)) &&
|
if ((!(val1 & 0x07)) &&
|
||||||
@ -761,48 +722,60 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
((val1 & 0x80) && (val2 != 0x06)))) {
|
((val1 & 0x80) && (val2 != 0x06)))) {
|
||||||
pr_debug("asb100.o: detect failed, "
|
pr_debug("asb100.o: detect failed, "
|
||||||
"bad chip id 0x%02x!\n", val2);
|
"bad chip id 0x%02x!\n", val2);
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto ERROR1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* kind < 0 */
|
} /* kind < 0 */
|
||||||
|
|
||||||
/* We have either had a force parameter, or we have already detected
|
/* We have either had a force parameter, or we have already detected
|
||||||
Winbond. Put it now into bank 0 and Vendor ID High Byte */
|
Winbond. Put it now into bank 0 and Vendor ID High Byte */
|
||||||
asb100_write_value(client, ASB100_REG_BANK,
|
i2c_smbus_write_byte_data(client, ASB100_REG_BANK,
|
||||||
(asb100_read_value(client, ASB100_REG_BANK) & 0x78) | 0x80);
|
(i2c_smbus_read_byte_data(client, ASB100_REG_BANK) & 0x78)
|
||||||
|
| 0x80);
|
||||||
|
|
||||||
/* Determine the chip type. */
|
/* Determine the chip type. */
|
||||||
if (kind <= 0) {
|
if (kind <= 0) {
|
||||||
int val1 = asb100_read_value(client, ASB100_REG_WCHIPID);
|
int val1 = i2c_smbus_read_byte_data(client, ASB100_REG_WCHIPID);
|
||||||
int val2 = asb100_read_value(client, ASB100_REG_CHIPMAN);
|
int val2 = i2c_smbus_read_byte_data(client, ASB100_REG_CHIPMAN);
|
||||||
|
|
||||||
if ((val1 == 0x31) && (val2 == 0x06))
|
if ((val1 == 0x31) && (val2 == 0x06))
|
||||||
kind = asb100;
|
kind = asb100;
|
||||||
else {
|
else {
|
||||||
if (kind == 0)
|
if (kind == 0)
|
||||||
dev_warn(&client->dev, "ignoring "
|
dev_warn(&adapter->dev, "ignoring "
|
||||||
"'force' parameter for unknown chip "
|
"'force' parameter for unknown chip "
|
||||||
"at adapter %d, address 0x%02x.\n",
|
"at adapter %d, address 0x%02x.\n",
|
||||||
i2c_adapter_id(adapter), address);
|
i2c_adapter_id(adapter), client->addr);
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto ERROR1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in remaining client fields and put it into the global list */
|
strlcpy(info->type, "asb100", I2C_NAME_SIZE);
|
||||||
strlcpy(client->name, "asb100", I2C_NAME_SIZE);
|
|
||||||
data->type = kind;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int asb100_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct asb100_data *data;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
pr_debug("asb100.o: probe failed, kzalloc failed!\n");
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto ERROR0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->lock);
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto ERROR1;
|
|
||||||
|
|
||||||
/* Attach secondary lm75 clients */
|
/* Attach secondary lm75 clients */
|
||||||
if ((err = asb100_detect_subclients(adapter, address, kind,
|
err = asb100_detect_subclients(client);
|
||||||
client)))
|
if (err)
|
||||||
goto ERROR2;
|
goto ERROR1;
|
||||||
|
|
||||||
/* Initialize the chip */
|
/* Initialize the chip */
|
||||||
asb100_init_client(client);
|
asb100_init_client(client);
|
||||||
@ -827,39 +800,25 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
ERROR4:
|
ERROR4:
|
||||||
sysfs_remove_group(&client->dev.kobj, &asb100_group);
|
sysfs_remove_group(&client->dev.kobj, &asb100_group);
|
||||||
ERROR3:
|
ERROR3:
|
||||||
i2c_detach_client(data->lm75[1]);
|
i2c_unregister_device(data->lm75[1]);
|
||||||
i2c_detach_client(data->lm75[0]);
|
i2c_unregister_device(data->lm75[0]);
|
||||||
kfree(data->lm75[1]);
|
|
||||||
kfree(data->lm75[0]);
|
|
||||||
ERROR2:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
ERROR1:
|
ERROR1:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
ERROR0:
|
ERROR0:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int asb100_detach_client(struct i2c_client *client)
|
static int asb100_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct asb100_data *data = i2c_get_clientdata(client);
|
struct asb100_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
/* main client */
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
if (data) {
|
sysfs_remove_group(&client->dev.kobj, &asb100_group);
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
|
||||||
sysfs_remove_group(&client->dev.kobj, &asb100_group);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
i2c_unregister_device(data->lm75[1]);
|
||||||
return err;
|
i2c_unregister_device(data->lm75[0]);
|
||||||
|
|
||||||
/* main client */
|
kfree(data);
|
||||||
if (data)
|
|
||||||
kfree(data);
|
|
||||||
|
|
||||||
/* subclient */
|
|
||||||
else
|
|
||||||
kfree(client);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -46,21 +46,32 @@ static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
|
|||||||
|
|
||||||
I2C_CLIENT_INSMOD_1(atxp1);
|
I2C_CLIENT_INSMOD_1(atxp1);
|
||||||
|
|
||||||
static int atxp1_attach_adapter(struct i2c_adapter * adapter);
|
static int atxp1_probe(struct i2c_client *client,
|
||||||
static int atxp1_detach_client(struct i2c_client * client);
|
const struct i2c_device_id *id);
|
||||||
|
static int atxp1_remove(struct i2c_client *client);
|
||||||
static struct atxp1_data * atxp1_update_device(struct device *dev);
|
static struct atxp1_data * atxp1_update_device(struct device *dev);
|
||||||
static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind);
|
static int atxp1_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
|
||||||
|
static const struct i2c_device_id atxp1_id[] = {
|
||||||
|
{ "atxp1", atxp1 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, atxp1_id);
|
||||||
|
|
||||||
static struct i2c_driver atxp1_driver = {
|
static struct i2c_driver atxp1_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "atxp1",
|
.name = "atxp1",
|
||||||
},
|
},
|
||||||
.attach_adapter = atxp1_attach_adapter,
|
.probe = atxp1_probe,
|
||||||
.detach_client = atxp1_detach_client,
|
.remove = atxp1_remove,
|
||||||
|
.id_table = atxp1_id,
|
||||||
|
.detect = atxp1_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct atxp1_data {
|
struct atxp1_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
unsigned long last_updated;
|
unsigned long last_updated;
|
||||||
@ -263,35 +274,16 @@ static const struct attribute_group atxp1_group = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int atxp1_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int atxp1_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, &atxp1_detect);
|
|
||||||
};
|
|
||||||
|
|
||||||
static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client * new_client;
|
|
||||||
struct atxp1_data * data;
|
|
||||||
int err = 0;
|
|
||||||
u8 temp;
|
u8 temp;
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct atxp1_data), GFP_KERNEL))) {
|
|
||||||
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 = &atxp1_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
/* Detect ATXP1, checking if vendor ID registers are all zero */
|
/* Detect ATXP1, checking if vendor ID registers are all zero */
|
||||||
if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
|
if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
|
||||||
@ -305,35 +297,46 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
|
if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
|
||||||
(i2c_smbus_read_byte_data(new_client, 0x11) == temp) ))
|
(i2c_smbus_read_byte_data(new_client, 0x11) == temp) ))
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get VRM */
|
||||||
|
temp = vid_which_vrm();
|
||||||
|
|
||||||
|
if ((temp != 90) && (temp != 91)) {
|
||||||
|
dev_err(&adapter->dev, "atxp1: Not supporting VRM %d.%d\n",
|
||||||
|
temp / 10, temp % 10);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(info->type, "atxp1", I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int atxp1_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct atxp1_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct atxp1_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get VRM */
|
/* Get VRM */
|
||||||
data->vrm = vid_which_vrm();
|
data->vrm = vid_which_vrm();
|
||||||
|
|
||||||
if ((data->vrm != 90) && (data->vrm != 91)) {
|
i2c_set_clientdata(new_client, data);
|
||||||
dev_err(&new_client->dev, "Not supporting VRM %d.%d\n",
|
|
||||||
data->vrm / 10, data->vrm % 10);
|
|
||||||
goto exit_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
strncpy(new_client->name, "atxp1", I2C_NAME_SIZE);
|
|
||||||
|
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
|
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
err = i2c_attach_client(new_client);
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
dev_err(&new_client->dev, "Attach client error.\n");
|
|
||||||
goto exit_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
|
if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -348,30 +351,22 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &atxp1_group);
|
sysfs_remove_group(&new_client->dev.kobj, &atxp1_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int atxp1_detach_client(struct i2c_client * client)
|
static int atxp1_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct atxp1_data * data = i2c_get_clientdata(client);
|
struct atxp1_data * data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &atxp1_group);
|
sysfs_remove_group(&client->dev.kobj, &atxp1_group);
|
||||||
|
|
||||||
err = i2c_detach_client(client);
|
kfree(data);
|
||||||
|
|
||||||
if (err)
|
return 0;
|
||||||
dev_err(&client->dev, "Failed to detach client.\n");
|
|
||||||
else
|
|
||||||
kfree(data);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init atxp1_init(void)
|
static int __init atxp1_init(void)
|
||||||
|
@ -72,7 +72,6 @@ static const u8 DS1621_REG_TEMP[3] = {
|
|||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct ds1621_data {
|
struct ds1621_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* !=0 if following fields are valid */
|
char valid; /* !=0 if following fields are valid */
|
||||||
@ -82,20 +81,32 @@ struct ds1621_data {
|
|||||||
u8 conf; /* Register encoding, combined */
|
u8 conf; /* Register encoding, combined */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ds1621_attach_adapter(struct i2c_adapter *adapter);
|
static int ds1621_probe(struct i2c_client *client,
|
||||||
static int ds1621_detect(struct i2c_adapter *adapter, int address,
|
const struct i2c_device_id *id);
|
||||||
int kind);
|
static int ds1621_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void ds1621_init_client(struct i2c_client *client);
|
static void ds1621_init_client(struct i2c_client *client);
|
||||||
static int ds1621_detach_client(struct i2c_client *client);
|
static int ds1621_remove(struct i2c_client *client);
|
||||||
static struct ds1621_data *ds1621_update_client(struct device *dev);
|
static struct ds1621_data *ds1621_update_client(struct device *dev);
|
||||||
|
|
||||||
|
static const struct i2c_device_id ds1621_id[] = {
|
||||||
|
{ "ds1621", ds1621 },
|
||||||
|
{ "ds1625", ds1621 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, ds1621_id);
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
/* This is the driver that will be inserted */
|
||||||
static struct i2c_driver ds1621_driver = {
|
static struct i2c_driver ds1621_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ds1621",
|
.name = "ds1621",
|
||||||
},
|
},
|
||||||
.attach_adapter = ds1621_attach_adapter,
|
.probe = ds1621_probe,
|
||||||
.detach_client = ds1621_detach_client,
|
.remove = ds1621_remove,
|
||||||
|
.id_table = ds1621_id,
|
||||||
|
.detect = ds1621_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* All registers are word-sized, except for the configuration register.
|
/* All registers are word-sized, except for the configuration register.
|
||||||
@ -199,40 +210,18 @@ static const struct attribute_group ds1621_group = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int ds1621_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
{
|
static int ds1621_detect(struct i2c_client *client, int kind,
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_board_info *info)
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, ds1621_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
|
||||||
static int ds1621_detect(struct i2c_adapter *adapter, int address,
|
|
||||||
int kind)
|
|
||||||
{
|
{
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
int conf, temp;
|
int conf, temp;
|
||||||
struct i2c_client *client;
|
int i;
|
||||||
struct ds1621_data *data;
|
|
||||||
int i, err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
|
||||||
| I2C_FUNC_SMBUS_WORD_DATA
|
| I2C_FUNC_SMBUS_WORD_DATA
|
||||||
| I2C_FUNC_SMBUS_WRITE_BYTE))
|
| I2C_FUNC_SMBUS_WRITE_BYTE))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access ds1621_{read,write}_value. */
|
|
||||||
if (!(data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &ds1621_driver;
|
|
||||||
|
|
||||||
/* Now, we do the remaining detection. It is lousy. */
|
/* Now, we do the remaining detection. It is lousy. */
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
@ -241,29 +230,41 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
|
|||||||
improbable in our case. */
|
improbable in our case. */
|
||||||
conf = ds1621_read_value(client, DS1621_REG_CONF);
|
conf = ds1621_read_value(client, DS1621_REG_CONF);
|
||||||
if (conf & DS1621_REG_CONFIG_NVB)
|
if (conf & DS1621_REG_CONFIG_NVB)
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
/* The 7 lowest bits of a temperature should always be 0. */
|
/* The 7 lowest bits of a temperature should always be 0. */
|
||||||
for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
|
for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
|
||||||
temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
|
temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
|
||||||
if (temp & 0x007f)
|
if (temp & 0x007f)
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in remaining client fields and put it into the global list */
|
strlcpy(info->type, "ds1621", I2C_NAME_SIZE);
|
||||||
strlcpy(client->name, "ds1621", I2C_NAME_SIZE);
|
|
||||||
mutex_init(&data->update_lock);
|
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
return 0;
|
||||||
if ((err = i2c_attach_client(client)))
|
}
|
||||||
goto exit_free;
|
|
||||||
|
static int ds1621_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct ds1621_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct ds1621_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Initialize the DS1621 chip */
|
/* Initialize the DS1621 chip */
|
||||||
ds1621_init_client(client);
|
ds1621_init_client(client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -275,25 +276,19 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
|
|||||||
|
|
||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
|
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ds1621_detach_client(struct i2c_client *client)
|
static int ds1621_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct ds1621_data *data = i2c_get_clientdata(client);
|
struct ds1621_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
|
sysfs_remove_group(&client->dev.kobj, &ds1621_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -87,7 +87,6 @@ I2C_CLIENT_INSMOD_2(f75373, f75375);
|
|||||||
|
|
||||||
struct f75375_data {
|
struct f75375_data {
|
||||||
unsigned short addr;
|
unsigned short addr;
|
||||||
struct i2c_client *client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
|
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -114,21 +113,12 @@ struct f75375_data {
|
|||||||
s8 temp_max_hyst[2];
|
s8 temp_max_hyst[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int f75375_attach_adapter(struct i2c_adapter *adapter);
|
static int f75375_detect(struct i2c_client *client, int kind,
|
||||||
static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
|
struct i2c_board_info *info);
|
||||||
static int f75375_detach_client(struct i2c_client *client);
|
|
||||||
static int f75375_probe(struct i2c_client *client,
|
static int f75375_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id);
|
const struct i2c_device_id *id);
|
||||||
static int f75375_remove(struct i2c_client *client);
|
static int f75375_remove(struct i2c_client *client);
|
||||||
|
|
||||||
static struct i2c_driver f75375_legacy_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "f75375_legacy",
|
|
||||||
},
|
|
||||||
.attach_adapter = f75375_attach_adapter,
|
|
||||||
.detach_client = f75375_detach_client,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct i2c_device_id f75375_id[] = {
|
static const struct i2c_device_id f75375_id[] = {
|
||||||
{ "f75373", f75373 },
|
{ "f75373", f75373 },
|
||||||
{ "f75375", f75375 },
|
{ "f75375", f75375 },
|
||||||
@ -137,12 +127,15 @@ static const struct i2c_device_id f75375_id[] = {
|
|||||||
MODULE_DEVICE_TABLE(i2c, f75375_id);
|
MODULE_DEVICE_TABLE(i2c, f75375_id);
|
||||||
|
|
||||||
static struct i2c_driver f75375_driver = {
|
static struct i2c_driver f75375_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "f75375",
|
.name = "f75375",
|
||||||
},
|
},
|
||||||
.probe = f75375_probe,
|
.probe = f75375_probe,
|
||||||
.remove = f75375_remove,
|
.remove = f75375_remove,
|
||||||
.id_table = f75375_id,
|
.id_table = f75375_id,
|
||||||
|
.detect = f75375_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int f75375_read8(struct i2c_client *client, u8 reg)
|
static inline int f75375_read8(struct i2c_client *client, u8 reg)
|
||||||
@ -607,22 +600,6 @@ static const struct attribute_group f75375_group = {
|
|||||||
.attrs = f75375_attributes,
|
.attrs = f75375_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int f75375_detach_client(struct i2c_client *client)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
f75375_remove(client);
|
|
||||||
err = i2c_detach_client(client);
|
|
||||||
if (err) {
|
|
||||||
dev_err(&client->dev,
|
|
||||||
"Client deregistration failed, "
|
|
||||||
"client not detached.\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
kfree(client);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void f75375_init(struct i2c_client *client, struct f75375_data *data,
|
static void f75375_init(struct i2c_client *client, struct f75375_data *data,
|
||||||
struct f75375s_platform_data *f75375s_pdata)
|
struct f75375s_platform_data *f75375s_pdata)
|
||||||
{
|
{
|
||||||
@ -651,7 +628,6 @@ static int f75375_probe(struct i2c_client *client,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
i2c_set_clientdata(client, data);
|
i2c_set_clientdata(client, data);
|
||||||
data->client = client;
|
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
data->kind = id->driver_data;
|
data->kind = id->driver_data;
|
||||||
|
|
||||||
@ -700,29 +676,13 @@ static int f75375_remove(struct i2c_client *client)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int f75375_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int f75375_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, f75375_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
|
||||||
static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
u8 version = 0;
|
u8 version = 0;
|
||||||
int err = 0;
|
|
||||||
const char *name = "";
|
const char *name = "";
|
||||||
struct i2c_device_id id;
|
|
||||||
|
|
||||||
if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &f75375_legacy_driver;
|
|
||||||
|
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
|
u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
|
||||||
@ -736,7 +696,7 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
dev_err(&adapter->dev,
|
dev_err(&adapter->dev,
|
||||||
"failed,%02X,%02X,%02X\n",
|
"failed,%02X,%02X,%02X\n",
|
||||||
chipid, version, vendid);
|
chipid, version, vendid);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,43 +706,18 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
name = "f75373";
|
name = "f75373";
|
||||||
}
|
}
|
||||||
dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
|
dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
|
||||||
strlcpy(client->name, name, I2C_NAME_SIZE);
|
strlcpy(info->type, name, I2C_NAME_SIZE);
|
||||||
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
strlcpy(id.name, name, I2C_NAME_SIZE);
|
|
||||||
id.driver_data = kind;
|
|
||||||
if ((err = f75375_probe(client, &id)) < 0)
|
|
||||||
goto exit_detach;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
|
||||||
kfree(client);
|
|
||||||
exit:
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init sensors_f75375_init(void)
|
static int __init sensors_f75375_init(void)
|
||||||
{
|
{
|
||||||
int status;
|
return i2c_add_driver(&f75375_driver);
|
||||||
status = i2c_add_driver(&f75375_driver);
|
|
||||||
if (status)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
status = i2c_add_driver(&f75375_legacy_driver);
|
|
||||||
if (status)
|
|
||||||
i2c_del_driver(&f75375_driver);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit sensors_f75375_exit(void)
|
static void __exit sensors_f75375_exit(void)
|
||||||
{
|
{
|
||||||
i2c_del_driver(&f75375_legacy_driver);
|
|
||||||
i2c_del_driver(&f75375_driver);
|
i2c_del_driver(&f75375_driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,9 +106,11 @@ I2C_CLIENT_INSMOD_1(fscher);
|
|||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int fscher_attach_adapter(struct i2c_adapter *adapter);
|
static int fscher_probe(struct i2c_client *client,
|
||||||
static int fscher_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int fscher_detach_client(struct i2c_client *client);
|
static int fscher_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int fscher_remove(struct i2c_client *client);
|
||||||
static struct fscher_data *fscher_update_device(struct device *dev);
|
static struct fscher_data *fscher_update_device(struct device *dev);
|
||||||
static void fscher_init_client(struct i2c_client *client);
|
static void fscher_init_client(struct i2c_client *client);
|
||||||
|
|
||||||
@ -119,12 +121,21 @@ static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value);
|
|||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id fscher_id[] = {
|
||||||
|
{ "fscher", fscher },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
static struct i2c_driver fscher_driver = {
|
static struct i2c_driver fscher_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "fscher",
|
.name = "fscher",
|
||||||
},
|
},
|
||||||
.attach_adapter = fscher_attach_adapter,
|
.probe = fscher_probe,
|
||||||
.detach_client = fscher_detach_client,
|
.remove = fscher_remove,
|
||||||
|
.id_table = fscher_id,
|
||||||
|
.detect = fscher_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -132,7 +143,6 @@ static struct i2c_driver fscher_driver = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct fscher_data {
|
struct fscher_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -283,38 +293,14 @@ static const struct attribute_group fscher_group = {
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int fscher_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int fscher_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, fscher_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *new_client;
|
|
||||||
struct fscher_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
* client structure, even though we cannot fill it completely yet.
|
|
||||||
* But it allows us to access i2c_smbus_read_byte_data. */
|
|
||||||
if (!(data = kzalloc(sizeof(struct fscher_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The common I2C client data is placed right before the
|
|
||||||
* Hermes-specific data. */
|
|
||||||
new_client = &data->client;
|
|
||||||
i2c_set_clientdata(new_client, data);
|
|
||||||
new_client->addr = address;
|
|
||||||
new_client->adapter = adapter;
|
|
||||||
new_client->driver = &fscher_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
/* Do the remaining detection unless force or force_fscher parameter */
|
/* Do the remaining detection unless force or force_fscher parameter */
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
@ -324,24 +310,35 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
FSCHER_REG_IDENT_1) != 0x45) /* 'E' */
|
FSCHER_REG_IDENT_1) != 0x45) /* 'E' */
|
||||||
|| (i2c_smbus_read_byte_data(new_client,
|
|| (i2c_smbus_read_byte_data(new_client,
|
||||||
FSCHER_REG_IDENT_2) != 0x52)) /* 'R' */
|
FSCHER_REG_IDENT_2) != 0x52)) /* 'R' */
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put it into the
|
strlcpy(info->type, "fscher", I2C_NAME_SIZE);
|
||||||
* global list */
|
|
||||||
strlcpy(new_client->name, "fscher", I2C_NAME_SIZE);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fscher_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct fscher_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct fscher_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(new_client, data);
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
fscher_init_client(new_client);
|
fscher_init_client(new_client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group)))
|
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -353,25 +350,19 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &fscher_group);
|
sysfs_remove_group(&new_client->dev.kobj, &fscher_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fscher_detach_client(struct i2c_client *client)
|
static int fscher_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct fscher_data *data = i2c_get_clientdata(client);
|
struct fscher_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &fscher_group);
|
sysfs_remove_group(&client->dev.kobj, &fscher_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -171,20 +171,37 @@ static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
|
|||||||
* Functions declarations
|
* Functions declarations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int fschmd_attach_adapter(struct i2c_adapter *adapter);
|
static int fschmd_probe(struct i2c_client *client,
|
||||||
static int fschmd_detach_client(struct i2c_client *client);
|
const struct i2c_device_id *id);
|
||||||
|
static int fschmd_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int fschmd_remove(struct i2c_client *client);
|
||||||
static struct fschmd_data *fschmd_update_device(struct device *dev);
|
static struct fschmd_data *fschmd_update_device(struct device *dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id fschmd_id[] = {
|
||||||
|
{ "fscpos", fscpos },
|
||||||
|
{ "fscher", fscher },
|
||||||
|
{ "fscscy", fscscy },
|
||||||
|
{ "fschrc", fschrc },
|
||||||
|
{ "fschmd", fschmd },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, fschmd_id);
|
||||||
|
|
||||||
static struct i2c_driver fschmd_driver = {
|
static struct i2c_driver fschmd_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = FSCHMD_NAME,
|
.name = FSCHMD_NAME,
|
||||||
},
|
},
|
||||||
.attach_adapter = fschmd_attach_adapter,
|
.probe = fschmd_probe,
|
||||||
.detach_client = fschmd_detach_client,
|
.remove = fschmd_remove,
|
||||||
|
.id_table = fschmd_id,
|
||||||
|
.detect = fschmd_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -192,7 +209,6 @@ static struct i2c_driver fschmd_driver = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct fschmd_data {
|
struct fschmd_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
int kind;
|
int kind;
|
||||||
@ -269,7 +285,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute
|
|||||||
v = SENSORS_LIMIT(v, -128, 127) + 128;
|
v = SENSORS_LIMIT(v, -128, 127) + 128;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
i2c_smbus_write_byte_data(&data->client,
|
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||||
FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
|
FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
|
||||||
data->temp_max[index] = v;
|
data->temp_max[index] = v;
|
||||||
mutex_unlock(&data->update_lock);
|
mutex_unlock(&data->update_lock);
|
||||||
@ -346,14 +362,14 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute
|
|||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
reg = i2c_smbus_read_byte_data(&data->client,
|
reg = i2c_smbus_read_byte_data(to_i2c_client(dev),
|
||||||
FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
|
FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
|
||||||
|
|
||||||
/* bits 2..7 reserved => mask with 0x03 */
|
/* bits 2..7 reserved => mask with 0x03 */
|
||||||
reg &= ~0x03;
|
reg &= ~0x03;
|
||||||
reg |= v;
|
reg |= v;
|
||||||
|
|
||||||
i2c_smbus_write_byte_data(&data->client,
|
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||||
FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
|
FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
|
||||||
|
|
||||||
data->fan_ripple[index] = reg;
|
data->fan_ripple[index] = reg;
|
||||||
@ -416,7 +432,7 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
|
|||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
i2c_smbus_write_byte_data(&data->client,
|
i2c_smbus_write_byte_data(to_i2c_client(dev),
|
||||||
FSCHMD_REG_FAN_MIN[data->kind][index], v);
|
FSCHMD_REG_FAN_MIN[data->kind][index], v);
|
||||||
data->fan_min[index] = v;
|
data->fan_min[index] = v;
|
||||||
|
|
||||||
@ -448,14 +464,14 @@ static ssize_t store_alert_led(struct device *dev,
|
|||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL);
|
reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL);
|
||||||
|
|
||||||
if (v)
|
if (v)
|
||||||
reg |= FSCHMD_CONTROL_ALERT_LED_MASK;
|
reg |= FSCHMD_CONTROL_ALERT_LED_MASK;
|
||||||
else
|
else
|
||||||
reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK;
|
reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK;
|
||||||
|
|
||||||
i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg);
|
i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg);
|
||||||
|
|
||||||
data->global_control = reg;
|
data->global_control = reg;
|
||||||
|
|
||||||
@ -600,32 +616,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
|
static int fschmd_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct i2c_client *client;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct fschmd_data *data;
|
|
||||||
u8 revision;
|
|
||||||
const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
|
|
||||||
"Heracles", "Heimdall" };
|
|
||||||
const char * const client_names[5] = { "fscpos", "fscher", "fscscy",
|
const char * const client_names[5] = { "fscpos", "fscher", "fscscy",
|
||||||
"fschrc", "fschmd" };
|
"fschrc", "fschmd" };
|
||||||
int i, err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
return 0;
|
return -ENODEV;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
* client structure, even though we cannot fill it completely yet.
|
|
||||||
* But it allows us to access i2c_smbus_read_byte_data. */
|
|
||||||
if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL)))
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &fschmd_driver;
|
|
||||||
mutex_init(&data->update_lock);
|
|
||||||
|
|
||||||
/* Detect & Identify the chip */
|
/* Detect & Identify the chip */
|
||||||
if (kind <= 0) {
|
if (kind <= 0) {
|
||||||
@ -650,9 +649,31 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
else if (!strcmp(id, "HMD"))
|
else if (!strcmp(id, "HMD"))
|
||||||
kind = fschmd;
|
kind = fschmd;
|
||||||
else
|
else
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fschmd_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct fschmd_data *data;
|
||||||
|
u8 revision;
|
||||||
|
const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
|
||||||
|
"Heracles", "Heimdall" };
|
||||||
|
int i, err;
|
||||||
|
enum chips kind = id->driver_data;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
if (kind == fscpos) {
|
if (kind == fscpos) {
|
||||||
/* The Poseidon has hardwired temp limits, fill these
|
/* The Poseidon has hardwired temp limits, fill these
|
||||||
in for the alarm resetting code */
|
in for the alarm resetting code */
|
||||||
@ -674,11 +695,6 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
/* i2c kind goes from 1-5, we want from 0-4 to address arrays */
|
/* i2c kind goes from 1-5, we want from 0-4 to address arrays */
|
||||||
data->kind = kind - 1;
|
data->kind = kind - 1;
|
||||||
strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE);
|
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {
|
for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) {
|
||||||
err = device_create_file(&client->dev,
|
err = device_create_file(&client->dev,
|
||||||
@ -726,25 +742,14 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exit_detach:
|
exit_detach:
|
||||||
fschmd_detach_client(client); /* will also free data for us */
|
fschmd_remove(client); /* will also free data for us */
|
||||||
return err;
|
|
||||||
|
|
||||||
exit_free:
|
|
||||||
kfree(data);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fschmd_attach_adapter(struct i2c_adapter *adapter)
|
static int fschmd_remove(struct i2c_client *client)
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, fschmd_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fschmd_detach_client(struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
struct fschmd_data *data = i2c_get_clientdata(client);
|
struct fschmd_data *data = i2c_get_clientdata(client);
|
||||||
int i, err;
|
int i;
|
||||||
|
|
||||||
/* Check if registered in case we're called from fschmd_detect
|
/* Check if registered in case we're called from fschmd_detect
|
||||||
to cleanup after an error */
|
to cleanup after an error */
|
||||||
@ -760,9 +765,6 @@ static int fschmd_detach_client(struct i2c_client *client)
|
|||||||
device_remove_file(&client->dev,
|
device_remove_file(&client->dev,
|
||||||
&fschmd_fan_attr[i].dev_attr);
|
&fschmd_fan_attr[i].dev_attr);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -87,9 +87,11 @@ static u8 FSCPOS_REG_TEMP_STATE[] = { 0x71, 0x81, 0x91 };
|
|||||||
/*
|
/*
|
||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
static int fscpos_attach_adapter(struct i2c_adapter *adapter);
|
static int fscpos_probe(struct i2c_client *client,
|
||||||
static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int fscpos_detach_client(struct i2c_client *client);
|
static int fscpos_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int fscpos_remove(struct i2c_client *client);
|
||||||
|
|
||||||
static int fscpos_read_value(struct i2c_client *client, u8 reg);
|
static int fscpos_read_value(struct i2c_client *client, u8 reg);
|
||||||
static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value);
|
static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value);
|
||||||
@ -101,19 +103,27 @@ static void reset_fan_alarm(struct i2c_client *client, int nr);
|
|||||||
/*
|
/*
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
static const struct i2c_device_id fscpos_id[] = {
|
||||||
|
{ "fscpos", fscpos },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
static struct i2c_driver fscpos_driver = {
|
static struct i2c_driver fscpos_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "fscpos",
|
.name = "fscpos",
|
||||||
},
|
},
|
||||||
.attach_adapter = fscpos_attach_adapter,
|
.probe = fscpos_probe,
|
||||||
.detach_client = fscpos_detach_client,
|
.remove = fscpos_remove,
|
||||||
|
.id_table = fscpos_id,
|
||||||
|
.detect = fscpos_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Client data (each client gets its own)
|
* Client data (each client gets its own)
|
||||||
*/
|
*/
|
||||||
struct fscpos_data {
|
struct fscpos_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* 0 until following fields are valid */
|
char valid; /* 0 until following fields are valid */
|
||||||
@ -470,39 +480,14 @@ static const struct attribute_group fscpos_group = {
|
|||||||
.attrs = fscpos_attributes,
|
.attrs = fscpos_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int fscpos_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int fscpos_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, fscpos_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *new_client;
|
|
||||||
struct fscpos_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/*
|
|
||||||
* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
* client structure, even though we cannot fill it completely yet.
|
|
||||||
* But it allows us to access fscpos_{read,write}_value.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct fscpos_data), GFP_KERNEL))) {
|
|
||||||
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 = &fscpos_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
/* Do the remaining detection unless force or force_fscpos parameter */
|
/* Do the remaining detection unless force or force_fscpos parameter */
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
@ -512,22 +497,30 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
!= 0x45) /* 'E' */
|
!= 0x45) /* 'E' */
|
||||||
|| (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2)
|
|| (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2)
|
||||||
!= 0x47))/* 'G' */
|
!= 0x47))/* 'G' */
|
||||||
{
|
return -ENODEV;
|
||||||
dev_dbg(&new_client->dev, "fscpos detection failed\n");
|
|
||||||
goto exit_free;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put it in the global list */
|
strlcpy(info->type, "fscpos", I2C_NAME_SIZE);
|
||||||
strlcpy(new_client->name, "fscpos", I2C_NAME_SIZE);
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fscpos_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct fscpos_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct fscpos_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(new_client, data);
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Inizialize the fscpos chip */
|
/* Inizialize the fscpos chip */
|
||||||
fscpos_init_client(new_client);
|
fscpos_init_client(new_client);
|
||||||
|
|
||||||
@ -536,7 +529,7 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
|
if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -548,24 +541,19 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &fscpos_group);
|
sysfs_remove_group(&new_client->dev.kobj, &fscpos_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fscpos_detach_client(struct i2c_client *client)
|
static int fscpos_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct fscpos_data *data = i2c_get_clientdata(client);
|
struct fscpos_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &fscpos_group);
|
sysfs_remove_group(&client->dev.kobj, &fscpos_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,6 @@ static inline u8 FAN_TO_REG(long rpm, int div)
|
|||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct gl518_data {
|
struct gl518_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
enum chips type;
|
enum chips type;
|
||||||
|
|
||||||
@ -138,21 +137,33 @@ struct gl518_data {
|
|||||||
u8 beep_enable; /* Boolean */
|
u8 beep_enable; /* Boolean */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int gl518_attach_adapter(struct i2c_adapter *adapter);
|
static int gl518_probe(struct i2c_client *client,
|
||||||
static int gl518_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
|
static int gl518_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void gl518_init_client(struct i2c_client *client);
|
static void gl518_init_client(struct i2c_client *client);
|
||||||
static int gl518_detach_client(struct i2c_client *client);
|
static int gl518_remove(struct i2c_client *client);
|
||||||
static int gl518_read_value(struct i2c_client *client, u8 reg);
|
static int gl518_read_value(struct i2c_client *client, u8 reg);
|
||||||
static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value);
|
static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value);
|
||||||
static struct gl518_data *gl518_update_device(struct device *dev);
|
static struct gl518_data *gl518_update_device(struct device *dev);
|
||||||
|
|
||||||
|
static const struct i2c_device_id gl518_id[] = {
|
||||||
|
{ "gl518sm", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, gl518_id);
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
/* This is the driver that will be inserted */
|
||||||
static struct i2c_driver gl518_driver = {
|
static struct i2c_driver gl518_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "gl518sm",
|
.name = "gl518sm",
|
||||||
},
|
},
|
||||||
.attach_adapter = gl518_attach_adapter,
|
.probe = gl518_probe,
|
||||||
.detach_client = gl518_detach_client,
|
.remove = gl518_remove,
|
||||||
|
.id_table = gl518_id,
|
||||||
|
.detect = gl518_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -472,46 +483,23 @@ static const struct attribute_group gl518_group_r80 = {
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int gl518_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
{
|
static int gl518_detect(struct i2c_client *client, int kind,
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_board_info *info)
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, gl518_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
{
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
int i;
|
int i;
|
||||||
struct i2c_client *client;
|
|
||||||
struct gl518_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||||
I2C_FUNC_SMBUS_WORD_DATA))
|
I2C_FUNC_SMBUS_WORD_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access gl518_{read,write}_value. */
|
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct gl518_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &gl518_driver;
|
|
||||||
|
|
||||||
/* Now, we do the remaining detection. */
|
/* Now, we do the remaining detection. */
|
||||||
|
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80)
|
if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80)
|
||||||
|| (gl518_read_value(client, GL518_REG_CONF) & 0x80))
|
|| (gl518_read_value(client, GL518_REG_CONF) & 0x80))
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the chip type. */
|
/* Determine the chip type. */
|
||||||
@ -526,19 +514,32 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
dev_info(&adapter->dev,
|
dev_info(&adapter->dev,
|
||||||
"Ignoring 'force' parameter for unknown "
|
"Ignoring 'force' parameter for unknown "
|
||||||
"chip at adapter %d, address 0x%02x\n",
|
"chip at adapter %d, address 0x%02x\n",
|
||||||
i2c_adapter_id(adapter), address);
|
i2c_adapter_id(adapter), client->addr);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the remaining client fields */
|
strlcpy(info->type, "gl518sm", I2C_NAME_SIZE);
|
||||||
strlcpy(client->name, "gl518sm", I2C_NAME_SIZE);
|
|
||||||
data->type = kind;
|
|
||||||
mutex_init(&data->update_lock);
|
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
return 0;
|
||||||
if ((err = i2c_attach_client(client)))
|
}
|
||||||
goto exit_free;
|
|
||||||
|
static int gl518_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct gl518_data *data;
|
||||||
|
int err, revision;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct gl518_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
revision = gl518_read_value(client, GL518_REG_REVISION);
|
||||||
|
data->type = revision == 0x80 ? gl518sm_r80 : gl518sm_r00;
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Initialize the GL518SM chip */
|
/* Initialize the GL518SM chip */
|
||||||
data->alarm_mask = 0xff;
|
data->alarm_mask = 0xff;
|
||||||
@ -546,7 +547,7 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &gl518_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &gl518_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
if (data->type == gl518sm_r80)
|
if (data->type == gl518sm_r80)
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj,
|
if ((err = sysfs_create_group(&client->dev.kobj,
|
||||||
&gl518_group_r80)))
|
&gl518_group_r80)))
|
||||||
@ -564,8 +565,6 @@ exit_remove_files:
|
|||||||
sysfs_remove_group(&client->dev.kobj, &gl518_group);
|
sysfs_remove_group(&client->dev.kobj, &gl518_group);
|
||||||
if (data->type == gl518sm_r80)
|
if (data->type == gl518sm_r80)
|
||||||
sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
|
sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
@ -591,19 +590,15 @@ static void gl518_init_client(struct i2c_client *client)
|
|||||||
gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue);
|
gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gl518_detach_client(struct i2c_client *client)
|
static int gl518_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct gl518_data *data = i2c_get_clientdata(client);
|
struct gl518_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &gl518_group);
|
sysfs_remove_group(&client->dev.kobj, &gl518_group);
|
||||||
if (data->type == gl518sm_r80)
|
if (data->type == gl518sm_r80)
|
||||||
sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
|
sysfs_remove_group(&client->dev.kobj, &gl518_group_r80);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -79,26 +79,37 @@ static const u8 GL520_REG_TEMP_MAX_HYST[] = { 0x06, 0x18 };
|
|||||||
* Function declarations
|
* Function declarations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int gl520_attach_adapter(struct i2c_adapter *adapter);
|
static int gl520_probe(struct i2c_client *client,
|
||||||
static int gl520_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
|
static int gl520_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void gl520_init_client(struct i2c_client *client);
|
static void gl520_init_client(struct i2c_client *client);
|
||||||
static int gl520_detach_client(struct i2c_client *client);
|
static int gl520_remove(struct i2c_client *client);
|
||||||
static int gl520_read_value(struct i2c_client *client, u8 reg);
|
static int gl520_read_value(struct i2c_client *client, u8 reg);
|
||||||
static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value);
|
static int gl520_write_value(struct i2c_client *client, u8 reg, u16 value);
|
||||||
static struct gl520_data *gl520_update_device(struct device *dev);
|
static struct gl520_data *gl520_update_device(struct device *dev);
|
||||||
|
|
||||||
/* Driver data */
|
/* Driver data */
|
||||||
|
static const struct i2c_device_id gl520_id[] = {
|
||||||
|
{ "gl520sm", gl520sm },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, gl520_id);
|
||||||
|
|
||||||
static struct i2c_driver gl520_driver = {
|
static struct i2c_driver gl520_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "gl520sm",
|
.name = "gl520sm",
|
||||||
},
|
},
|
||||||
.attach_adapter = gl520_attach_adapter,
|
.probe = gl520_probe,
|
||||||
.detach_client = gl520_detach_client,
|
.remove = gl520_remove,
|
||||||
|
.id_table = gl520_id,
|
||||||
|
.detect = gl520_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Client data */
|
/* Client data */
|
||||||
struct gl520_data {
|
struct gl520_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until the following fields are valid */
|
char valid; /* zero until the following fields are valid */
|
||||||
@ -669,37 +680,15 @@ static const struct attribute_group gl520_group_opt = {
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int gl520_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int gl520_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, gl520_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
struct gl520_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||||
I2C_FUNC_SMBUS_WORD_DATA))
|
I2C_FUNC_SMBUS_WORD_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access gl520_{read,write}_value. */
|
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct gl520_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &gl520_driver;
|
|
||||||
|
|
||||||
/* Determine the chip type. */
|
/* Determine the chip type. */
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
@ -707,24 +696,36 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
|
((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) ||
|
||||||
((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) {
|
((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) {
|
||||||
dev_dbg(&client->dev, "Unknown chip type, skipping\n");
|
dev_dbg(&client->dev, "Unknown chip type, skipping\n");
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the remaining client fields */
|
strlcpy(info->type, "gl520sm", I2C_NAME_SIZE);
|
||||||
strlcpy(client->name, "gl520sm", I2C_NAME_SIZE);
|
|
||||||
mutex_init(&data->update_lock);
|
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
return 0;
|
||||||
if ((err = i2c_attach_client(client)))
|
}
|
||||||
goto exit_free;
|
|
||||||
|
static int gl520_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct gl520_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct gl520_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Initialize the GL520SM chip */
|
/* Initialize the GL520SM chip */
|
||||||
gl520_init_client(client);
|
gl520_init_client(client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
if (data->two_temps) {
|
if (data->two_temps) {
|
||||||
if ((err = device_create_file(&client->dev,
|
if ((err = device_create_file(&client->dev,
|
||||||
@ -764,8 +765,6 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&client->dev.kobj, &gl520_group);
|
sysfs_remove_group(&client->dev.kobj, &gl520_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
|
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
@ -811,18 +810,14 @@ static void gl520_init_client(struct i2c_client *client)
|
|||||||
gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
|
gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gl520_detach_client(struct i2c_client *client)
|
static int gl520_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct gl520_data *data = i2c_get_clientdata(client);
|
struct gl520_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &gl520_group);
|
sysfs_remove_group(&client->dev.kobj, &gl520_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
|
sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* lm63.c - driver for the National Semiconductor LM63 temperature sensor
|
* lm63.c - driver for the National Semiconductor LM63 temperature sensor
|
||||||
* with integrated fan control
|
* with integrated fan control
|
||||||
* Copyright (C) 2004-2006 Jean Delvare <khali@linux-fr.org>
|
* Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
|
||||||
* Based on the lm90 driver.
|
* Based on the lm90 driver.
|
||||||
*
|
*
|
||||||
* The LM63 is a sensor chip made by National Semiconductor. It measures
|
* The LM63 is a sensor chip made by National Semiconductor. It measures
|
||||||
@ -128,24 +128,36 @@ I2C_CLIENT_INSMOD_1(lm63);
|
|||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int lm63_attach_adapter(struct i2c_adapter *adapter);
|
static int lm63_probe(struct i2c_client *client,
|
||||||
static int lm63_detach_client(struct i2c_client *client);
|
const struct i2c_device_id *id);
|
||||||
|
static int lm63_remove(struct i2c_client *client);
|
||||||
|
|
||||||
static struct lm63_data *lm63_update_device(struct device *dev);
|
static struct lm63_data *lm63_update_device(struct device *dev);
|
||||||
|
|
||||||
static int lm63_detect(struct i2c_adapter *adapter, int address, int kind);
|
static int lm63_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void lm63_init_client(struct i2c_client *client);
|
static void lm63_init_client(struct i2c_client *client);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id lm63_id[] = {
|
||||||
|
{ "lm63", lm63 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, lm63_id);
|
||||||
|
|
||||||
static struct i2c_driver lm63_driver = {
|
static struct i2c_driver lm63_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "lm63",
|
.name = "lm63",
|
||||||
},
|
},
|
||||||
.attach_adapter = lm63_attach_adapter,
|
.probe = lm63_probe,
|
||||||
.detach_client = lm63_detach_client,
|
.remove = lm63_remove,
|
||||||
|
.id_table = lm63_id,
|
||||||
|
.detect = lm63_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -153,7 +165,6 @@ static struct i2c_driver lm63_driver = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct lm63_data {
|
struct lm63_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -411,43 +422,14 @@ static const struct attribute_group lm63_group_fan1 = {
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int lm63_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int lm63_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, lm63_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following function does more than just detection. If detection
|
|
||||||
* succeeds, it also registers the new chip.
|
|
||||||
*/
|
|
||||||
static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *new_client;
|
|
||||||
struct lm63_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The common I2C client data is placed right before the
|
|
||||||
LM63-specific data. */
|
|
||||||
new_client = &data->client;
|
|
||||||
i2c_set_clientdata(new_client, data);
|
|
||||||
new_client->addr = address;
|
|
||||||
new_client->adapter = adapter;
|
|
||||||
new_client->driver = &lm63_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
/* Default to an LM63 if forced */
|
|
||||||
if (kind == 0)
|
|
||||||
kind = lm63;
|
|
||||||
|
|
||||||
if (kind < 0) { /* must identify */
|
if (kind < 0) { /* must identify */
|
||||||
u8 man_id, chip_id, reg_config1, reg_config2;
|
u8 man_id, chip_id, reg_config1, reg_config2;
|
||||||
@ -477,25 +459,38 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
dev_dbg(&adapter->dev, "Unsupported chip "
|
dev_dbg(&adapter->dev, "Unsupported chip "
|
||||||
"(man_id=0x%02X, chip_id=0x%02X).\n",
|
"(man_id=0x%02X, chip_id=0x%02X).\n",
|
||||||
man_id, chip_id);
|
man_id, chip_id);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strlcpy(new_client->name, "lm63", I2C_NAME_SIZE);
|
strlcpy(info->type, "lm63", I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lm63_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct lm63_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct lm63_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(new_client, data);
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Initialize the LM63 chip */
|
/* Initialize the LM63 chip */
|
||||||
lm63_init_client(new_client);
|
lm63_init_client(new_client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
||||||
&lm63_group)))
|
&lm63_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
if (data->config & 0x04) { /* tachometer enabled */
|
if (data->config & 0x04) { /* tachometer enabled */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
||||||
&lm63_group_fan1)))
|
&lm63_group_fan1)))
|
||||||
@ -513,8 +508,6 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
|
sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
|
sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
@ -556,18 +549,14 @@ static void lm63_init_client(struct i2c_client *client)
|
|||||||
(data->config_fan & 0x20) ? "manual" : "auto");
|
(data->config_fan & 0x20) ? "manual" : "auto");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lm63_detach_client(struct i2c_client *client)
|
static int lm63_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct lm63_data *data = i2c_get_clientdata(client);
|
struct lm63_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm63_group);
|
sysfs_remove_group(&client->dev.kobj, &lm63_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
|
sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,6 @@ I2C_CLIENT_INSMOD_1(lm77);
|
|||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct lm77_data {
|
struct lm77_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid;
|
char valid;
|
||||||
@ -65,23 +64,35 @@ struct lm77_data {
|
|||||||
u8 alarms;
|
u8 alarms;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int lm77_attach_adapter(struct i2c_adapter *adapter);
|
static int lm77_probe(struct i2c_client *client,
|
||||||
static int lm77_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
|
static int lm77_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void lm77_init_client(struct i2c_client *client);
|
static void lm77_init_client(struct i2c_client *client);
|
||||||
static int lm77_detach_client(struct i2c_client *client);
|
static int lm77_remove(struct i2c_client *client);
|
||||||
static u16 lm77_read_value(struct i2c_client *client, u8 reg);
|
static u16 lm77_read_value(struct i2c_client *client, u8 reg);
|
||||||
static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value);
|
static int lm77_write_value(struct i2c_client *client, u8 reg, u16 value);
|
||||||
|
|
||||||
static struct lm77_data *lm77_update_device(struct device *dev);
|
static struct lm77_data *lm77_update_device(struct device *dev);
|
||||||
|
|
||||||
|
|
||||||
|
static const struct i2c_device_id lm77_id[] = {
|
||||||
|
{ "lm77", lm77 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, lm77_id);
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
/* This is the driver that will be inserted */
|
||||||
static struct i2c_driver lm77_driver = {
|
static struct i2c_driver lm77_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "lm77",
|
.name = "lm77",
|
||||||
},
|
},
|
||||||
.attach_adapter = lm77_attach_adapter,
|
.probe = lm77_probe,
|
||||||
.detach_client = lm77_detach_client,
|
.remove = lm77_remove,
|
||||||
|
.id_table = lm77_id,
|
||||||
|
.detect = lm77_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* straight from the datasheet */
|
/* straight from the datasheet */
|
||||||
@ -215,13 +226,6 @@ static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);
|
|||||||
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
|
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
|
||||||
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
|
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
|
||||||
|
|
||||||
static int lm77_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, lm77_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct attribute *lm77_attributes[] = {
|
static struct attribute *lm77_attributes[] = {
|
||||||
&dev_attr_temp1_input.attr,
|
&dev_attr_temp1_input.attr,
|
||||||
&dev_attr_temp1_crit.attr,
|
&dev_attr_temp1_crit.attr,
|
||||||
@ -240,32 +244,15 @@ static const struct attribute_group lm77_group = {
|
|||||||
.attrs = lm77_attributes,
|
.attrs = lm77_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
|
static int lm77_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct i2c_client *new_client;
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
struct lm77_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *name = "";
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||||
I2C_FUNC_SMBUS_WORD_DATA))
|
I2C_FUNC_SMBUS_WORD_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access lm77_{read,write}_value. */
|
|
||||||
if (!(data = kzalloc(sizeof(struct lm77_data), GFP_KERNEL))) {
|
|
||||||
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 = &lm77_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
/* Here comes the remaining detection. Since the LM77 has no
|
/* Here comes the remaining detection. Since the LM77 has no
|
||||||
register dedicated to identification, we have to rely on the
|
register dedicated to identification, we have to rely on the
|
||||||
@ -294,7 +281,7 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|| i2c_smbus_read_word_data(new_client, i + 3) != crit
|
|| i2c_smbus_read_word_data(new_client, i + 3) != crit
|
||||||
|| i2c_smbus_read_word_data(new_client, i + 4) != min
|
|| i2c_smbus_read_word_data(new_client, i + 4) != min
|
||||||
|| i2c_smbus_read_word_data(new_client, i + 5) != max)
|
|| i2c_smbus_read_word_data(new_client, i + 5) != max)
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
|
|
||||||
/* sign bits */
|
/* sign bits */
|
||||||
if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0)
|
if (((cur & 0x00f0) != 0xf0 && (cur & 0x00f0) != 0x0)
|
||||||
@ -302,51 +289,55 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|| ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0)
|
|| ((crit & 0x00f0) != 0xf0 && (crit & 0x00f0) != 0x0)
|
||||||
|| ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0)
|
|| ((min & 0x00f0) != 0xf0 && (min & 0x00f0) != 0x0)
|
||||||
|| ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0))
|
|| ((max & 0x00f0) != 0xf0 && (max & 0x00f0) != 0x0))
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
|
|
||||||
/* unused bits */
|
/* unused bits */
|
||||||
if (conf & 0xe0)
|
if (conf & 0xe0)
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
|
|
||||||
/* 0x06 and 0x07 return the last read value */
|
/* 0x06 and 0x07 return the last read value */
|
||||||
cur = i2c_smbus_read_word_data(new_client, 0);
|
cur = i2c_smbus_read_word_data(new_client, 0);
|
||||||
if (i2c_smbus_read_word_data(new_client, 6) != cur
|
if (i2c_smbus_read_word_data(new_client, 6) != cur
|
||||||
|| i2c_smbus_read_word_data(new_client, 7) != cur)
|
|| i2c_smbus_read_word_data(new_client, 7) != cur)
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
hyst = i2c_smbus_read_word_data(new_client, 2);
|
hyst = i2c_smbus_read_word_data(new_client, 2);
|
||||||
if (i2c_smbus_read_word_data(new_client, 6) != hyst
|
if (i2c_smbus_read_word_data(new_client, 6) != hyst
|
||||||
|| i2c_smbus_read_word_data(new_client, 7) != hyst)
|
|| i2c_smbus_read_word_data(new_client, 7) != hyst)
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
min = i2c_smbus_read_word_data(new_client, 4);
|
min = i2c_smbus_read_word_data(new_client, 4);
|
||||||
if (i2c_smbus_read_word_data(new_client, 6) != min
|
if (i2c_smbus_read_word_data(new_client, 6) != min
|
||||||
|| i2c_smbus_read_word_data(new_client, 7) != min)
|
|| i2c_smbus_read_word_data(new_client, 7) != min)
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the chip type - only one kind supported! */
|
strlcpy(info->type, "lm77", I2C_NAME_SIZE);
|
||||||
if (kind <= 0)
|
|
||||||
kind = lm77;
|
|
||||||
|
|
||||||
if (kind == lm77) {
|
return 0;
|
||||||
name = "lm77";
|
}
|
||||||
|
|
||||||
|
static int lm77_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct lm77_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct lm77_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put it into the global list */
|
i2c_set_clientdata(new_client, data);
|
||||||
strlcpy(new_client->name, name, I2C_NAME_SIZE);
|
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Initialize the LM77 chip */
|
/* Initialize the LM77 chip */
|
||||||
lm77_init_client(new_client);
|
lm77_init_client(new_client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
|
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -358,20 +349,17 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm77_group);
|
sysfs_remove_group(&new_client->dev.kobj, &lm77_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lm77_detach_client(struct i2c_client *client)
|
static int lm77_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct lm77_data *data = i2c_get_clientdata(client);
|
struct lm77_data *data = i2c_get_clientdata(client);
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm77_group);
|
sysfs_remove_group(&client->dev.kobj, &lm77_group);
|
||||||
i2c_detach_client(client);
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,6 @@ static inline long TEMP_FROM_REG(u16 temp)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct lm80_data {
|
struct lm80_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* !=0 if following fields are valid */
|
char valid; /* !=0 if following fields are valid */
|
||||||
@ -132,10 +131,12 @@ struct lm80_data {
|
|||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int lm80_attach_adapter(struct i2c_adapter *adapter);
|
static int lm80_probe(struct i2c_client *client,
|
||||||
static int lm80_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
|
static int lm80_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void lm80_init_client(struct i2c_client *client);
|
static void lm80_init_client(struct i2c_client *client);
|
||||||
static int lm80_detach_client(struct i2c_client *client);
|
static int lm80_remove(struct i2c_client *client);
|
||||||
static struct lm80_data *lm80_update_device(struct device *dev);
|
static struct lm80_data *lm80_update_device(struct device *dev);
|
||||||
static int lm80_read_value(struct i2c_client *client, u8 reg);
|
static int lm80_read_value(struct i2c_client *client, u8 reg);
|
||||||
static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
|
static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
|
||||||
@ -144,12 +145,22 @@ static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
|
|||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id lm80_id[] = {
|
||||||
|
{ "lm80", lm80 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, lm80_id);
|
||||||
|
|
||||||
static struct i2c_driver lm80_driver = {
|
static struct i2c_driver lm80_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "lm80",
|
.name = "lm80",
|
||||||
},
|
},
|
||||||
.attach_adapter = lm80_attach_adapter,
|
.probe = lm80_probe,
|
||||||
.detach_client = lm80_detach_client,
|
.remove = lm80_remove,
|
||||||
|
.id_table = lm80_id,
|
||||||
|
.detect = lm80_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -383,13 +394,6 @@ static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 13);
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int lm80_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, lm80_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct attribute *lm80_attributes[] = {
|
static struct attribute *lm80_attributes[] = {
|
||||||
&sensor_dev_attr_in0_min.dev_attr.attr,
|
&sensor_dev_attr_in0_min.dev_attr.attr,
|
||||||
&sensor_dev_attr_in1_min.dev_attr.attr,
|
&sensor_dev_attr_in1_min.dev_attr.attr,
|
||||||
@ -442,54 +446,47 @@ static const struct attribute_group lm80_group = {
|
|||||||
.attrs = lm80_attributes,
|
.attrs = lm80_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int lm80_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
int i, cur;
|
int i, cur;
|
||||||
struct i2c_client *client;
|
|
||||||
struct lm80_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access lm80_{read,write}_value. */
|
|
||||||
if (!(data = kzalloc(sizeof(struct lm80_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &lm80_driver;
|
|
||||||
|
|
||||||
/* Now, we do the remaining detection. It is lousy. */
|
/* Now, we do the remaining detection. It is lousy. */
|
||||||
if (lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
|
if (lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
|
||||||
goto error_free;
|
return -ENODEV;
|
||||||
for (i = 0x2a; i <= 0x3d; i++) {
|
for (i = 0x2a; i <= 0x3d; i++) {
|
||||||
cur = i2c_smbus_read_byte_data(client, i);
|
cur = i2c_smbus_read_byte_data(client, i);
|
||||||
if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur)
|
if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur)
|
||||||
|| (i2c_smbus_read_byte_data(client, i + 0x80) != cur)
|
|| (i2c_smbus_read_byte_data(client, i + 0x80) != cur)
|
||||||
|| (i2c_smbus_read_byte_data(client, i + 0xc0) != cur))
|
|| (i2c_smbus_read_byte_data(client, i + 0xc0) != cur))
|
||||||
goto error_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the chip type - only one kind supported! */
|
strlcpy(info->type, "lm80", I2C_NAME_SIZE);
|
||||||
kind = lm80;
|
|
||||||
name = "lm80";
|
|
||||||
|
|
||||||
/* Fill in the remaining client fields */
|
return 0;
|
||||||
strlcpy(client->name, name, I2C_NAME_SIZE);
|
}
|
||||||
|
|
||||||
|
static int lm80_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct lm80_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct lm80_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto error_free;
|
|
||||||
|
|
||||||
/* Initialize the LM80 chip */
|
/* Initialize the LM80 chip */
|
||||||
lm80_init_client(client);
|
lm80_init_client(client);
|
||||||
|
|
||||||
@ -499,7 +496,7 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &lm80_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &lm80_group)))
|
||||||
goto error_detach;
|
goto error_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -511,23 +508,18 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
error_remove:
|
error_remove:
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm80_group);
|
sysfs_remove_group(&client->dev.kobj, &lm80_group);
|
||||||
error_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
error_free:
|
error_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lm80_detach_client(struct i2c_client *client)
|
static int lm80_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct lm80_data *data = i2c_get_clientdata(client);
|
struct lm80_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm80_group);
|
sysfs_remove_group(&client->dev.kobj, &lm80_group);
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
|
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||||
* monitoring
|
* monitoring
|
||||||
* Copyright (C) 2003-2006 Jean Delvare <khali@linux-fr.org>
|
* Copyright (C) 2003-2008 Jean Delvare <khali@linux-fr.org>
|
||||||
*
|
*
|
||||||
* Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
|
* Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
|
||||||
* a sensor chip made by National Semiconductor. It reports up to four
|
* a sensor chip made by National Semiconductor. It reports up to four
|
||||||
@ -118,21 +118,34 @@ static const u8 LM83_REG_W_HIGH[] = {
|
|||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int lm83_attach_adapter(struct i2c_adapter *adapter);
|
static int lm83_detect(struct i2c_client *new_client, int kind,
|
||||||
static int lm83_detect(struct i2c_adapter *adapter, int address, int kind);
|
struct i2c_board_info *info);
|
||||||
static int lm83_detach_client(struct i2c_client *client);
|
static int lm83_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id);
|
||||||
|
static int lm83_remove(struct i2c_client *client);
|
||||||
static struct lm83_data *lm83_update_device(struct device *dev);
|
static struct lm83_data *lm83_update_device(struct device *dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id lm83_id[] = {
|
||||||
|
{ "lm83", lm83 },
|
||||||
|
{ "lm82", lm82 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, lm83_id);
|
||||||
|
|
||||||
static struct i2c_driver lm83_driver = {
|
static struct i2c_driver lm83_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "lm83",
|
.name = "lm83",
|
||||||
},
|
},
|
||||||
.attach_adapter = lm83_attach_adapter,
|
.probe = lm83_probe,
|
||||||
.detach_client = lm83_detach_client,
|
.remove = lm83_remove,
|
||||||
|
.id_table = lm83_id,
|
||||||
|
.detect = lm83_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -140,7 +153,6 @@ static struct i2c_driver lm83_driver = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct lm83_data {
|
struct lm83_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -278,40 +290,15 @@ static const struct attribute_group lm83_group_opt = {
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int lm83_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int lm83_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, lm83_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following function does more than just detection. If detection
|
|
||||||
* succeeds, it also registers the new chip.
|
|
||||||
*/
|
|
||||||
static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *new_client;
|
|
||||||
struct lm83_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *name = "";
|
const char *name = "";
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct lm83_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The common I2C client data is placed right after the
|
|
||||||
* LM83-specific data. */
|
|
||||||
new_client = &data->client;
|
|
||||||
i2c_set_clientdata(new_client, data);
|
|
||||||
new_client->addr = address;
|
|
||||||
new_client->adapter = adapter;
|
|
||||||
new_client->driver = &lm83_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
/* Now we do the detection and identification. A negative kind
|
/* Now we do the detection and identification. A negative kind
|
||||||
* means that the driver was loaded with no force parameter
|
* means that the driver was loaded with no force parameter
|
||||||
@ -335,8 +322,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG)
|
((i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG)
|
||||||
& 0x41) != 0x00)) {
|
& 0x41) != 0x00)) {
|
||||||
dev_dbg(&adapter->dev,
|
dev_dbg(&adapter->dev,
|
||||||
"LM83 detection failed at 0x%02x.\n", address);
|
"LM83 detection failed at 0x%02x.\n",
|
||||||
goto exit_free;
|
new_client->addr);
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +349,7 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
dev_info(&adapter->dev,
|
dev_info(&adapter->dev,
|
||||||
"Unsupported chip (man_id=0x%02X, "
|
"Unsupported chip (man_id=0x%02X, "
|
||||||
"chip_id=0x%02X).\n", man_id, chip_id);
|
"chip_id=0x%02X).\n", man_id, chip_id);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,15 +360,27 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
name = "lm82";
|
name = "lm82";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can fill in the remaining client fields */
|
strlcpy(info->type, name, I2C_NAME_SIZE);
|
||||||
strlcpy(new_client->name, name, I2C_NAME_SIZE);
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lm83_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct lm83_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct lm83_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(new_client, data);
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register sysfs hooks
|
* Register sysfs hooks
|
||||||
* The LM82 can only monitor one external diode which is
|
* The LM82 can only monitor one external diode which is
|
||||||
@ -389,9 +389,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm83_group)))
|
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm83_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
if (kind == lm83) {
|
if (id->driver_data == lm83) {
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
if ((err = sysfs_create_group(&new_client->dev.kobj,
|
||||||
&lm83_group_opt)))
|
&lm83_group_opt)))
|
||||||
goto exit_remove_files;
|
goto exit_remove_files;
|
||||||
@ -408,26 +408,20 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm83_group);
|
sysfs_remove_group(&new_client->dev.kobj, &lm83_group);
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt);
|
sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lm83_detach_client(struct i2c_client *client)
|
static int lm83_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct lm83_data *data = i2c_get_clientdata(client);
|
struct lm83_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm83_group);
|
sysfs_remove_group(&client->dev.kobj, &lm83_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
|
sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Philip Edelbrock <phil@netroedge.com>
|
* Philip Edelbrock <phil@netroedge.com>
|
||||||
* Stephen Rousset <stephen.rousset@rocketlogix.com>
|
* Stephen Rousset <stephen.rousset@rocketlogix.com>
|
||||||
* Dan Eaton <dan.eaton@rocketlogix.com>
|
* Dan Eaton <dan.eaton@rocketlogix.com>
|
||||||
* Copyright (C) 2004,2007 Jean Delvare <khali@linux-fr.org>
|
* Copyright (C) 2004-2008 Jean Delvare <khali@linux-fr.org>
|
||||||
*
|
*
|
||||||
* Original port to Linux 2.6 by Jeff Oliver.
|
* Original port to Linux 2.6 by Jeff Oliver.
|
||||||
*
|
*
|
||||||
@ -157,22 +157,35 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C };
|
|||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int lm87_attach_adapter(struct i2c_adapter *adapter);
|
static int lm87_probe(struct i2c_client *client,
|
||||||
static int lm87_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
|
static int lm87_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void lm87_init_client(struct i2c_client *client);
|
static void lm87_init_client(struct i2c_client *client);
|
||||||
static int lm87_detach_client(struct i2c_client *client);
|
static int lm87_remove(struct i2c_client *client);
|
||||||
static struct lm87_data *lm87_update_device(struct device *dev);
|
static struct lm87_data *lm87_update_device(struct device *dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id lm87_id[] = {
|
||||||
|
{ "lm87", lm87 },
|
||||||
|
{ "adm1024", adm1024 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, lm87_id);
|
||||||
|
|
||||||
static struct i2c_driver lm87_driver = {
|
static struct i2c_driver lm87_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "lm87",
|
.name = "lm87",
|
||||||
},
|
},
|
||||||
.attach_adapter = lm87_attach_adapter,
|
.probe = lm87_probe,
|
||||||
.detach_client = lm87_detach_client,
|
.remove = lm87_remove,
|
||||||
|
.id_table = lm87_id,
|
||||||
|
.detect = lm87_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -180,7 +193,6 @@ static struct i2c_driver lm87_driver = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct lm87_data {
|
struct lm87_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -562,13 +574,6 @@ static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15);
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int lm87_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, lm87_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct attribute *lm87_attributes[] = {
|
static struct attribute *lm87_attributes[] = {
|
||||||
&dev_attr_in1_input.attr,
|
&dev_attr_in1_input.attr,
|
||||||
&dev_attr_in1_min.attr,
|
&dev_attr_in1_min.attr,
|
||||||
@ -656,33 +661,15 @@ static const struct attribute_group lm87_group_opt = {
|
|||||||
.attrs = lm87_attributes_opt,
|
.attrs = lm87_attributes_opt,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
* The following function does more than just detection. If detection
|
static int lm87_detect(struct i2c_client *new_client, int kind,
|
||||||
* succeeds, it also registers the new chip.
|
struct i2c_board_info *info)
|
||||||
*/
|
|
||||||
static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
{
|
||||||
struct i2c_client *new_client;
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
struct lm87_data *data;
|
|
||||||
int err = 0;
|
|
||||||
static const char *names[] = { "lm87", "adm1024" };
|
static const char *names[] = { "lm87", "adm1024" };
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct lm87_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The common I2C client data is placed right before the
|
|
||||||
LM87-specific data. */
|
|
||||||
new_client = &data->client;
|
|
||||||
i2c_set_clientdata(new_client, data);
|
|
||||||
new_client->addr = address;
|
|
||||||
new_client->adapter = adapter;
|
|
||||||
new_client->driver = &lm87_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
/* Default to an LM87 if forced */
|
/* Default to an LM87 if forced */
|
||||||
if (kind == 0)
|
if (kind == 0)
|
||||||
@ -704,20 +691,32 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|| (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)) {
|
|| (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)) {
|
||||||
dev_dbg(&adapter->dev,
|
dev_dbg(&adapter->dev,
|
||||||
"LM87 detection failed at 0x%02x.\n",
|
"LM87 detection failed at 0x%02x.\n",
|
||||||
address);
|
new_client->addr);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can fill in the remaining client fields */
|
strlcpy(info->type, names[kind - 1], I2C_NAME_SIZE);
|
||||||
strlcpy(new_client->name, names[kind - 1], I2C_NAME_SIZE);
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lm87_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct lm87_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct lm87_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(new_client, data);
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Initialize the LM87 chip */
|
/* Initialize the LM87 chip */
|
||||||
lm87_init_client(new_client);
|
lm87_init_client(new_client);
|
||||||
|
|
||||||
@ -732,7 +731,7 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm87_group)))
|
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm87_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
if (data->channel & CHAN_NO_FAN(0)) {
|
if (data->channel & CHAN_NO_FAN(0)) {
|
||||||
if ((err = device_create_file(&new_client->dev,
|
if ((err = device_create_file(&new_client->dev,
|
||||||
@ -832,8 +831,6 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm87_group);
|
sysfs_remove_group(&new_client->dev.kobj, &lm87_group);
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm87_group_opt);
|
sysfs_remove_group(&new_client->dev.kobj, &lm87_group_opt);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
@ -877,18 +874,14 @@ static void lm87_init_client(struct i2c_client *client)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lm87_detach_client(struct i2c_client *client)
|
static int lm87_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct lm87_data *data = i2c_get_clientdata(client);
|
struct lm87_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm87_group);
|
sysfs_remove_group(&client->dev.kobj, &lm87_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
|
sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -187,23 +187,44 @@ I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680);
|
|||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int lm90_attach_adapter(struct i2c_adapter *adapter);
|
static int lm90_detect(struct i2c_client *client, int kind,
|
||||||
static int lm90_detect(struct i2c_adapter *adapter, int address,
|
struct i2c_board_info *info);
|
||||||
int kind);
|
static int lm90_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id);
|
||||||
static void lm90_init_client(struct i2c_client *client);
|
static void lm90_init_client(struct i2c_client *client);
|
||||||
static int lm90_detach_client(struct i2c_client *client);
|
static int lm90_remove(struct i2c_client *client);
|
||||||
static struct lm90_data *lm90_update_device(struct device *dev);
|
static struct lm90_data *lm90_update_device(struct device *dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id lm90_id[] = {
|
||||||
|
{ "adm1032", adm1032 },
|
||||||
|
{ "adt7461", adt7461 },
|
||||||
|
{ "lm90", lm90 },
|
||||||
|
{ "lm86", lm86 },
|
||||||
|
{ "lm89", lm99 },
|
||||||
|
{ "lm99", lm99 }, /* Missing temperature offset */
|
||||||
|
{ "max6657", max6657 },
|
||||||
|
{ "max6658", max6657 },
|
||||||
|
{ "max6659", max6657 },
|
||||||
|
{ "max6680", max6680 },
|
||||||
|
{ "max6681", max6680 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, lm90_id);
|
||||||
|
|
||||||
static struct i2c_driver lm90_driver = {
|
static struct i2c_driver lm90_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "lm90",
|
.name = "lm90",
|
||||||
},
|
},
|
||||||
.attach_adapter = lm90_attach_adapter,
|
.probe = lm90_probe,
|
||||||
.detach_client = lm90_detach_client,
|
.remove = lm90_remove,
|
||||||
|
.id_table = lm90_id,
|
||||||
|
.detect = lm90_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -211,7 +232,6 @@ static struct i2c_driver lm90_driver = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct lm90_data {
|
struct lm90_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -477,40 +497,16 @@ static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lm90_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int lm90_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
return 0;
|
int address = new_client->addr;
|
||||||
return i2c_probe(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 = "";
|
const char *name = "";
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct lm90_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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
|
* Now we do the remaining detection. A negative kind means that
|
||||||
@ -538,7 +534,7 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
LM90_REG_R_CONFIG1)) < 0
|
LM90_REG_R_CONFIG1)) < 0
|
||||||
|| (reg_convrate = i2c_smbus_read_byte_data(new_client,
|
|| (reg_convrate = i2c_smbus_read_byte_data(new_client,
|
||||||
LM90_REG_R_CONVRATE)) < 0)
|
LM90_REG_R_CONVRATE)) < 0)
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
|
|
||||||
if ((address == 0x4C || address == 0x4D)
|
if ((address == 0x4C || address == 0x4D)
|
||||||
&& man_id == 0x01) { /* National Semiconductor */
|
&& man_id == 0x01) { /* National Semiconductor */
|
||||||
@ -546,7 +542,7 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
if ((reg_config2 = i2c_smbus_read_byte_data(new_client,
|
if ((reg_config2 = i2c_smbus_read_byte_data(new_client,
|
||||||
LM90_REG_R_CONFIG2)) < 0)
|
LM90_REG_R_CONFIG2)) < 0)
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
|
|
||||||
if ((reg_config1 & 0x2A) == 0x00
|
if ((reg_config1 & 0x2A) == 0x00
|
||||||
&& (reg_config2 & 0xF8) == 0x00
|
&& (reg_config2 & 0xF8) == 0x00
|
||||||
@ -610,10 +606,11 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
dev_info(&adapter->dev,
|
dev_info(&adapter->dev,
|
||||||
"Unsupported chip (man_id=0x%02X, "
|
"Unsupported chip (man_id=0x%02X, "
|
||||||
"chip_id=0x%02X).\n", man_id, chip_id);
|
"chip_id=0x%02X).\n", man_id, chip_id);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fill the i2c board info */
|
||||||
if (kind == lm90) {
|
if (kind == lm90) {
|
||||||
name = "lm90";
|
name = "lm90";
|
||||||
} else if (kind == adm1032) {
|
} else if (kind == adm1032) {
|
||||||
@ -621,7 +618,7 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
/* The ADM1032 supports PEC, but only if combined
|
/* The ADM1032 supports PEC, but only if combined
|
||||||
transactions are not used. */
|
transactions are not used. */
|
||||||
if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
|
if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
|
||||||
new_client->flags |= I2C_CLIENT_PEC;
|
info->flags |= I2C_CLIENT_PEC;
|
||||||
} else if (kind == lm99) {
|
} else if (kind == lm99) {
|
||||||
name = "lm99";
|
name = "lm99";
|
||||||
} else if (kind == lm86) {
|
} else if (kind == lm86) {
|
||||||
@ -633,23 +630,39 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
} else if (kind == adt7461) {
|
} else if (kind == adt7461) {
|
||||||
name = "adt7461";
|
name = "adt7461";
|
||||||
}
|
}
|
||||||
|
strlcpy(info->type, name, I2C_NAME_SIZE);
|
||||||
|
|
||||||
/* We can fill in the remaining client fields */
|
return 0;
|
||||||
strlcpy(new_client->name, name, I2C_NAME_SIZE);
|
}
|
||||||
data->valid = 0;
|
|
||||||
data->kind = kind;
|
static int lm90_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct i2c_adapter *adapter = to_i2c_adapter(new_client->dev.parent);
|
||||||
|
struct lm90_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct lm90_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
i2c_set_clientdata(new_client, data);
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
/* Set the device type */
|
||||||
if ((err = i2c_attach_client(new_client)))
|
data->kind = id->driver_data;
|
||||||
goto exit_free;
|
if (data->kind == adm1032) {
|
||||||
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
|
||||||
|
new_client->flags &= ~I2C_CLIENT_PEC;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize the LM90 chip */
|
/* Initialize the LM90 chip */
|
||||||
lm90_init_client(new_client);
|
lm90_init_client(new_client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group)))
|
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
if (new_client->flags & I2C_CLIENT_PEC) {
|
if (new_client->flags & I2C_CLIENT_PEC) {
|
||||||
if ((err = device_create_file(&new_client->dev,
|
if ((err = device_create_file(&new_client->dev,
|
||||||
&dev_attr_pec)))
|
&dev_attr_pec)))
|
||||||
@ -672,8 +685,6 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm90_group);
|
sysfs_remove_group(&new_client->dev.kobj, &lm90_group);
|
||||||
device_remove_file(&new_client->dev, &dev_attr_pec);
|
device_remove_file(&new_client->dev, &dev_attr_pec);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
@ -710,10 +721,9 @@ static void lm90_init_client(struct i2c_client *client)
|
|||||||
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
|
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lm90_detach_client(struct i2c_client *client)
|
static int lm90_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct lm90_data *data = i2c_get_clientdata(client);
|
struct lm90_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm90_group);
|
sysfs_remove_group(&client->dev.kobj, &lm90_group);
|
||||||
@ -722,9 +732,6 @@ static int lm90_detach_client(struct i2c_client *client)
|
|||||||
device_remove_file(&client->dev,
|
device_remove_file(&client->dev,
|
||||||
&sensor_dev_attr_temp2_offset.dev_attr);
|
&sensor_dev_attr_temp2_offset.dev_attr);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* lm92 - Hardware monitoring driver
|
* lm92 - Hardware monitoring driver
|
||||||
* Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
|
* Copyright (C) 2005-2008 Jean Delvare <khali@linux-fr.org>
|
||||||
*
|
*
|
||||||
* Based on the lm90 driver, with some ideas taken from the lm_sensors
|
* Based on the lm90 driver, with some ideas taken from the lm_sensors
|
||||||
* lm92 driver as well.
|
* lm92 driver as well.
|
||||||
@ -96,7 +96,6 @@ static struct i2c_driver lm92_driver;
|
|||||||
|
|
||||||
/* Client data (each client gets its own) */
|
/* Client data (each client gets its own) */
|
||||||
struct lm92_data {
|
struct lm92_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -319,32 +318,15 @@ static const struct attribute_group lm92_group = {
|
|||||||
.attrs = lm92_attributes,
|
.attrs = lm92_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The following function does more than just detection. If detection
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
succeeds, it also registers the new chip. */
|
static int lm92_detect(struct i2c_client *new_client, int kind,
|
||||||
static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct i2c_client *new_client;
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
struct lm92_data *data;
|
|
||||||
int err = 0;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
|
||||||
| I2C_FUNC_SMBUS_WORD_DATA))
|
| I2C_FUNC_SMBUS_WORD_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct lm92_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fill in enough client fields so that we can read from the chip,
|
|
||||||
which is required for identication */
|
|
||||||
new_client = &data->client;
|
|
||||||
i2c_set_clientdata(new_client, data);
|
|
||||||
new_client->addr = address;
|
|
||||||
new_client->adapter = adapter;
|
|
||||||
new_client->driver = &lm92_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
/* A negative kind means that the driver was loaded with no force
|
/* A negative kind means that the driver was loaded with no force
|
||||||
parameter (default), so we must identify the chip. */
|
parameter (default), so we must identify the chip. */
|
||||||
@ -364,34 +346,36 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
kind = lm92; /* No separate prefix */
|
kind = lm92; /* No separate prefix */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
} else
|
|
||||||
if (kind == 0) /* Default to an LM92 if forced */
|
|
||||||
kind = lm92;
|
|
||||||
|
|
||||||
/* Give it the proper name */
|
|
||||||
if (kind == lm92) {
|
|
||||||
name = "lm92";
|
|
||||||
} else { /* Supposedly cannot happen */
|
|
||||||
dev_dbg(&new_client->dev, "Kind out of range?\n");
|
|
||||||
goto exit_free;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the remaining client fields */
|
strlcpy(info->type, "lm92", I2C_NAME_SIZE);
|
||||||
strlcpy(new_client->name, name, I2C_NAME_SIZE);
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lm92_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct lm92_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct lm92_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(new_client, data);
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the i2c subsystem a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Initialize the chipset */
|
/* Initialize the chipset */
|
||||||
lm92_init_client(new_client);
|
lm92_init_client(new_client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
|
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -403,32 +387,19 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &lm92_group);
|
sysfs_remove_group(&new_client->dev.kobj, &lm92_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lm92_attach_adapter(struct i2c_adapter *adapter)
|
static int lm92_remove(struct i2c_client *client)
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, lm92_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm92_detach_client(struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
struct lm92_data *data = i2c_get_clientdata(client);
|
struct lm92_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm92_group);
|
sysfs_remove_group(&client->dev.kobj, &lm92_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -438,12 +409,23 @@ static int lm92_detach_client(struct i2c_client *client)
|
|||||||
* Module and driver stuff
|
* Module and driver stuff
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id lm92_id[] = {
|
||||||
|
{ "lm92", lm92 },
|
||||||
|
/* max6635 could be added here */
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, lm92_id);
|
||||||
|
|
||||||
static struct i2c_driver lm92_driver = {
|
static struct i2c_driver lm92_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "lm92",
|
.name = "lm92",
|
||||||
},
|
},
|
||||||
.attach_adapter = lm92_attach_adapter,
|
.probe = lm92_probe,
|
||||||
.detach_client = lm92_detach_client,
|
.remove = lm92_remove,
|
||||||
|
.id_table = lm92_id,
|
||||||
|
.detect = lm92_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init sensors_lm92_init(void)
|
static int __init sensors_lm92_init(void)
|
||||||
|
@ -200,7 +200,6 @@ struct block1_t {
|
|||||||
* Client-specific data
|
* Client-specific data
|
||||||
*/
|
*/
|
||||||
struct lm93_data {
|
struct lm93_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
|
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
@ -2501,45 +2500,14 @@ static void lm93_init_client(struct i2c_client *client)
|
|||||||
"chip to signal ready!\n");
|
"chip to signal ready!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int lm93_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct lm93_data *data;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct i2c_client *client;
|
|
||||||
|
|
||||||
int err = -ENODEV, func;
|
if (!i2c_check_functionality(adapter, LM93_SMBUS_FUNC_MIN))
|
||||||
void (*update)(struct lm93_data *, struct i2c_client *);
|
return -ENODEV;
|
||||||
|
|
||||||
/* choose update routine based on bus capabilities */
|
|
||||||
func = i2c_get_functionality(adapter);
|
|
||||||
if ( ((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) &&
|
|
||||||
(!disable_block) ) {
|
|
||||||
dev_dbg(&adapter->dev,"using SMBus block data transactions\n");
|
|
||||||
update = lm93_update_client_full;
|
|
||||||
} else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
|
|
||||||
dev_dbg(&adapter->dev,"disabled SMBus block data "
|
|
||||||
"transactions\n");
|
|
||||||
update = lm93_update_client_min;
|
|
||||||
} else {
|
|
||||||
dev_dbg(&adapter->dev,"detect failed, "
|
|
||||||
"smbus byte and/or word data not supported!\n");
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access lm78_{read,write}_value. */
|
|
||||||
|
|
||||||
if ( !(data = kzalloc(sizeof(struct lm93_data), GFP_KERNEL))) {
|
|
||||||
dev_dbg(&adapter->dev,"out of memory!\n");
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &lm93_driver;
|
|
||||||
|
|
||||||
/* detection */
|
/* detection */
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
@ -2548,7 +2516,7 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
if (mfr != 0x01) {
|
if (mfr != 0x01) {
|
||||||
dev_dbg(&adapter->dev,"detect failed, "
|
dev_dbg(&adapter->dev,"detect failed, "
|
||||||
"bad manufacturer id 0x%02x!\n", mfr);
|
"bad manufacturer id 0x%02x!\n", mfr);
|
||||||
goto err_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2563,31 +2531,61 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
if (kind == 0)
|
if (kind == 0)
|
||||||
dev_dbg(&adapter->dev,
|
dev_dbg(&adapter->dev,
|
||||||
"(ignored 'force' parameter)\n");
|
"(ignored 'force' parameter)\n");
|
||||||
goto err_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fill in remaining client fields */
|
strlcpy(info->type, "lm93", I2C_NAME_SIZE);
|
||||||
strlcpy(client->name, "lm93", I2C_NAME_SIZE);
|
|
||||||
dev_dbg(&adapter->dev,"loading %s at %d,0x%02x\n",
|
dev_dbg(&adapter->dev,"loading %s at %d,0x%02x\n",
|
||||||
client->name, i2c_adapter_id(client->adapter),
|
client->name, i2c_adapter_id(client->adapter),
|
||||||
client->addr);
|
client->addr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lm93_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct lm93_data *data;
|
||||||
|
int err, func;
|
||||||
|
void (*update)(struct lm93_data *, struct i2c_client *);
|
||||||
|
|
||||||
|
/* choose update routine based on bus capabilities */
|
||||||
|
func = i2c_get_functionality(client->adapter);
|
||||||
|
if (((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) &&
|
||||||
|
(!disable_block)) {
|
||||||
|
dev_dbg(&client->dev, "using SMBus block data transactions\n");
|
||||||
|
update = lm93_update_client_full;
|
||||||
|
} else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
|
||||||
|
dev_dbg(&client->dev, "disabled SMBus block data "
|
||||||
|
"transactions\n");
|
||||||
|
update = lm93_update_client_min;
|
||||||
|
} else {
|
||||||
|
dev_dbg(&client->dev, "detect failed, "
|
||||||
|
"smbus byte and/or word data not supported!\n");
|
||||||
|
err = -ENODEV;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct lm93_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
dev_dbg(&client->dev, "out of memory!\n");
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
|
||||||
/* housekeeping */
|
/* housekeeping */
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
data->update = update;
|
data->update = update;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto err_free;
|
|
||||||
|
|
||||||
/* initialize the chip */
|
/* initialize the chip */
|
||||||
lm93_init_client(client);
|
lm93_init_client(client);
|
||||||
|
|
||||||
err = sysfs_create_group(&client->dev.kobj, &lm93_attr_grp);
|
err = sysfs_create_group(&client->dev.kobj, &lm93_attr_grp);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_detach;
|
goto err_free;
|
||||||
|
|
||||||
/* Register hwmon driver class */
|
/* Register hwmon driver class */
|
||||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
@ -2597,43 +2595,39 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
err = PTR_ERR(data->hwmon_dev);
|
err = PTR_ERR(data->hwmon_dev);
|
||||||
dev_err(&client->dev, "error registering hwmon device.\n");
|
dev_err(&client->dev, "error registering hwmon device.\n");
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
|
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
|
||||||
err_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
err_free:
|
err_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
err_out:
|
err_out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called when:
|
static int lm93_remove(struct i2c_client *client)
|
||||||
* lm93_driver is inserted (when this module is loaded), for each
|
|
||||||
available adapter
|
|
||||||
* when a new adapter is inserted (and lm93_driver is still present) */
|
|
||||||
static int lm93_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
return i2c_probe(adapter, &addr_data, lm93_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lm93_detach_client(struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
struct lm93_data *data = i2c_get_clientdata(client);
|
struct lm93_data *data = i2c_get_clientdata(client);
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
|
sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
|
||||||
|
|
||||||
err = i2c_detach_client(client);
|
kfree(data);
|
||||||
if (!err)
|
return 0;
|
||||||
kfree(data);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id lm93_id[] = {
|
||||||
|
{ "lm93", lm93 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, lm93_id);
|
||||||
|
|
||||||
static struct i2c_driver lm93_driver = {
|
static struct i2c_driver lm93_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "lm93",
|
.name = "lm93",
|
||||||
},
|
},
|
||||||
.attach_adapter = lm93_attach_adapter,
|
.probe = lm93_probe,
|
||||||
.detach_client = lm93_detach_client,
|
.remove = lm93_remove,
|
||||||
|
.id_table = lm93_id,
|
||||||
|
.detect = lm93_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init lm93_init(void)
|
static int __init lm93_init(void)
|
||||||
|
@ -79,23 +79,34 @@ I2C_CLIENT_INSMOD_1(max1619);
|
|||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int max1619_attach_adapter(struct i2c_adapter *adapter);
|
static int max1619_probe(struct i2c_client *client,
|
||||||
static int max1619_detect(struct i2c_adapter *adapter, int address,
|
const struct i2c_device_id *id);
|
||||||
int kind);
|
static int max1619_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static void max1619_init_client(struct i2c_client *client);
|
static void max1619_init_client(struct i2c_client *client);
|
||||||
static int max1619_detach_client(struct i2c_client *client);
|
static int max1619_remove(struct i2c_client *client);
|
||||||
static struct max1619_data *max1619_update_device(struct device *dev);
|
static struct max1619_data *max1619_update_device(struct device *dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id max1619_id[] = {
|
||||||
|
{ "max1619", max1619 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, max1619_id);
|
||||||
|
|
||||||
static struct i2c_driver max1619_driver = {
|
static struct i2c_driver max1619_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "max1619",
|
.name = "max1619",
|
||||||
},
|
},
|
||||||
.attach_adapter = max1619_attach_adapter,
|
.probe = max1619_probe,
|
||||||
.detach_client = max1619_detach_client,
|
.remove = max1619_remove,
|
||||||
|
.id_table = max1619_id,
|
||||||
|
.detect = max1619_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -103,7 +114,6 @@ static struct i2c_driver max1619_driver = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct max1619_data {
|
struct max1619_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -208,41 +218,15 @@ static const struct attribute_group max1619_group = {
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int max1619_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int max1619_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, max1619_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following function does more than just detection. If detection
|
|
||||||
* succeeds, it also registers the new chip.
|
|
||||||
*/
|
|
||||||
static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *new_client;
|
|
||||||
struct max1619_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *name = "";
|
|
||||||
u8 reg_config=0, reg_convrate=0, reg_status=0;
|
u8 reg_config=0, reg_convrate=0, reg_status=0;
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct max1619_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The common I2C client data is placed right before the
|
|
||||||
MAX1619-specific data. */
|
|
||||||
new_client = &data->client;
|
|
||||||
i2c_set_clientdata(new_client, data);
|
|
||||||
new_client->addr = address;
|
|
||||||
new_client->adapter = adapter;
|
|
||||||
new_client->driver = &max1619_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we do the remaining detection. A negative kind means that
|
* Now we do the remaining detection. A negative kind means that
|
||||||
@ -265,8 +249,8 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|| reg_convrate > 0x07 || (reg_status & 0x61 ) !=0x00) {
|
|| reg_convrate > 0x07 || (reg_status & 0x61 ) !=0x00) {
|
||||||
dev_dbg(&adapter->dev,
|
dev_dbg(&adapter->dev,
|
||||||
"MAX1619 detection failed at 0x%02x.\n",
|
"MAX1619 detection failed at 0x%02x.\n",
|
||||||
address);
|
new_client->addr);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,28 +269,37 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
dev_info(&adapter->dev,
|
dev_info(&adapter->dev,
|
||||||
"Unsupported chip (man_id=0x%02X, "
|
"Unsupported chip (man_id=0x%02X, "
|
||||||
"chip_id=0x%02X).\n", man_id, chip_id);
|
"chip_id=0x%02X).\n", man_id, chip_id);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kind == max1619)
|
strlcpy(info->type, "max1619", I2C_NAME_SIZE);
|
||||||
name = "max1619";
|
|
||||||
|
|
||||||
/* We can fill in the remaining client fields */
|
return 0;
|
||||||
strlcpy(new_client->name, name, I2C_NAME_SIZE);
|
}
|
||||||
|
|
||||||
|
static int max1619_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct max1619_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct max1619_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(new_client, data);
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Initialize the MAX1619 chip */
|
/* Initialize the MAX1619 chip */
|
||||||
max1619_init_client(new_client);
|
max1619_init_client(new_client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
|
if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
data->hwmon_dev = hwmon_device_register(&new_client->dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
@ -318,8 +311,6 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&new_client->dev.kobj, &max1619_group);
|
sysfs_remove_group(&new_client->dev.kobj, &max1619_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
@ -341,17 +332,13 @@ static void max1619_init_client(struct i2c_client *client)
|
|||||||
config & 0xBF); /* run */
|
config & 0xBF); /* run */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int max1619_detach_client(struct i2c_client *client)
|
static int max1619_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct max1619_data *data = i2c_get_clientdata(client);
|
struct max1619_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &max1619_group);
|
sysfs_remove_group(&client->dev.kobj, &max1619_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -104,22 +104,34 @@ I2C_CLIENT_INSMOD_1(max6650);
|
|||||||
|
|
||||||
#define DIV_FROM_REG(reg) (1 << (reg & 7))
|
#define DIV_FROM_REG(reg) (1 << (reg & 7))
|
||||||
|
|
||||||
static int max6650_attach_adapter(struct i2c_adapter *adapter);
|
static int max6650_probe(struct i2c_client *client,
|
||||||
static int max6650_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
|
static int max6650_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
static int max6650_init_client(struct i2c_client *client);
|
static int max6650_init_client(struct i2c_client *client);
|
||||||
static int max6650_detach_client(struct i2c_client *client);
|
static int max6650_remove(struct i2c_client *client);
|
||||||
static struct max6650_data *max6650_update_device(struct device *dev);
|
static struct max6650_data *max6650_update_device(struct device *dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id max6650_id[] = {
|
||||||
|
{ "max6650", max6650 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, max6650_id);
|
||||||
|
|
||||||
static struct i2c_driver max6650_driver = {
|
static struct i2c_driver max6650_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "max6650",
|
.name = "max6650",
|
||||||
},
|
},
|
||||||
.attach_adapter = max6650_attach_adapter,
|
.probe = max6650_probe,
|
||||||
.detach_client = max6650_detach_client,
|
.remove = max6650_remove,
|
||||||
|
.id_table = max6650_id,
|
||||||
|
.detect = max6650_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -128,7 +140,6 @@ static struct i2c_driver max6650_driver = {
|
|||||||
|
|
||||||
struct max6650_data
|
struct max6650_data
|
||||||
{
|
{
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -437,47 +448,21 @@ static struct attribute_group max6650_attr_grp = {
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int max6650_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int max6650_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON)) {
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
dev_dbg(&adapter->dev,
|
int address = client->addr;
|
||||||
"FATAL: max6650_attach_adapter class HWMON not set\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i2c_probe(adapter, &addr_data, max6650_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following function does more than just detection. If detection
|
|
||||||
* succeeds, it also registers the new chip.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
struct max6650_data *data;
|
|
||||||
int err = -ENODEV;
|
|
||||||
|
|
||||||
dev_dbg(&adapter->dev, "max6650_detect called, kind = %d\n", kind);
|
dev_dbg(&adapter->dev, "max6650_detect called, kind = %d\n", kind);
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support "
|
dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support "
|
||||||
"byte read mode, skipping.\n");
|
"byte read mode, skipping.\n");
|
||||||
return 0;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL))) {
|
|
||||||
dev_err(&adapter->dev, "max6650: out of memory.\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &max6650_driver;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we do the remaining detection. A negative kind means that
|
* Now we do the remaining detection. A negative kind means that
|
||||||
* the driver was loaded with no force parameter (default), so we
|
* the driver was loaded with no force parameter (default), so we
|
||||||
@ -501,28 +486,40 @@ static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) {
|
||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) {
|
||||||
dev_dbg(&adapter->dev,
|
dev_dbg(&adapter->dev,
|
||||||
"max6650: detection failed at 0x%02x.\n", address);
|
"max6650: detection failed at 0x%02x.\n", address);
|
||||||
goto err_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address);
|
dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address);
|
||||||
|
|
||||||
strlcpy(client->name, "max6650", I2C_NAME_SIZE);
|
strlcpy(info->type, "max6650", I2C_NAME_SIZE);
|
||||||
mutex_init(&data->update_lock);
|
|
||||||
|
|
||||||
if ((err = i2c_attach_client(client))) {
|
return 0;
|
||||||
dev_err(&adapter->dev, "max6650: failed to attach client.\n");
|
}
|
||||||
goto err_free;
|
|
||||||
|
static int max6650_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct max6650_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!(data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL))) {
|
||||||
|
dev_err(&client->dev, "out of memory.\n");
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the max6650 chip
|
* Initialize the max6650 chip
|
||||||
*/
|
*/
|
||||||
if (max6650_init_client(client))
|
err = max6650_init_client(client);
|
||||||
goto err_detach;
|
if (err)
|
||||||
|
goto err_free;
|
||||||
|
|
||||||
err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
|
err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_detach;
|
goto err_free;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
if (!IS_ERR(data->hwmon_dev))
|
if (!IS_ERR(data->hwmon_dev))
|
||||||
@ -531,24 +528,19 @@ static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
err = PTR_ERR(data->hwmon_dev);
|
err = PTR_ERR(data->hwmon_dev);
|
||||||
dev_err(&client->dev, "error registering hwmon device.\n");
|
dev_err(&client->dev, "error registering hwmon device.\n");
|
||||||
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
|
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
|
||||||
err_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
err_free:
|
err_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int max6650_detach_client(struct i2c_client *client)
|
static int max6650_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct max6650_data *data = i2c_get_clientdata(client);
|
struct max6650_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
|
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
err = i2c_detach_client(client);
|
kfree(data);
|
||||||
if (!err)
|
return 0;
|
||||||
kfree(data);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int max6650_init_client(struct i2c_client *client)
|
static int max6650_init_client(struct i2c_client *client)
|
||||||
|
@ -96,7 +96,6 @@ static inline int TEMP_FROM_REG(s8 val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct smsc47m192_data {
|
struct smsc47m192_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* !=0 if following fields are valid */
|
char valid; /* !=0 if following fields are valid */
|
||||||
@ -114,18 +113,29 @@ struct smsc47m192_data {
|
|||||||
u8 vrm;
|
u8 vrm;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int smsc47m192_attach_adapter(struct i2c_adapter *adapter);
|
static int smsc47m192_probe(struct i2c_client *client,
|
||||||
static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
|
const struct i2c_device_id *id);
|
||||||
int kind);
|
static int smsc47m192_detect(struct i2c_client *client, int kind,
|
||||||
static int smsc47m192_detach_client(struct i2c_client *client);
|
struct i2c_board_info *info);
|
||||||
|
static int smsc47m192_remove(struct i2c_client *client);
|
||||||
static struct smsc47m192_data *smsc47m192_update_device(struct device *dev);
|
static struct smsc47m192_data *smsc47m192_update_device(struct device *dev);
|
||||||
|
|
||||||
|
static const struct i2c_device_id smsc47m192_id[] = {
|
||||||
|
{ "smsc47m192", smsc47m192 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, smsc47m192_id);
|
||||||
|
|
||||||
static struct i2c_driver smsc47m192_driver = {
|
static struct i2c_driver smsc47m192_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "smsc47m192",
|
.name = "smsc47m192",
|
||||||
},
|
},
|
||||||
.attach_adapter = smsc47m192_attach_adapter,
|
.probe = smsc47m192_probe,
|
||||||
.detach_client = smsc47m192_detach_client,
|
.remove = smsc47m192_remove,
|
||||||
|
.id_table = smsc47m192_id,
|
||||||
|
.detect = smsc47m192_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Voltages */
|
/* Voltages */
|
||||||
@ -440,17 +450,6 @@ static const struct attribute_group smsc47m192_group_in4 = {
|
|||||||
.attrs = smsc47m192_attributes_in4,
|
.attrs = smsc47m192_attributes_in4,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This function is called when:
|
|
||||||
* smsc47m192_driver is inserted (when this module is loaded), for each
|
|
||||||
available adapter
|
|
||||||
* when a new adapter is inserted (and smsc47m192_driver is still present) */
|
|
||||||
static int smsc47m192_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, smsc47m192_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void smsc47m192_init_client(struct i2c_client *client)
|
static void smsc47m192_init_client(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -481,31 +480,15 @@ static void smsc47m192_init_client(struct i2c_client *client)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
|
static int smsc47m192_detect(struct i2c_client *client, int kind,
|
||||||
int kind)
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct i2c_client *client;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct smsc47m192_data *data;
|
int version;
|
||||||
int err = 0;
|
|
||||||
int version, config;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &smsc47m192_driver;
|
|
||||||
|
|
||||||
if (kind == 0)
|
|
||||||
kind = smsc47m192;
|
|
||||||
|
|
||||||
/* Detection criteria from sensors_detect script */
|
/* Detection criteria from sensors_detect script */
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
@ -523,26 +506,39 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
|
|||||||
} else {
|
} else {
|
||||||
dev_dbg(&adapter->dev,
|
dev_dbg(&adapter->dev,
|
||||||
"SMSC47M192 detection failed at 0x%02x\n",
|
"SMSC47M192 detection failed at 0x%02x\n",
|
||||||
address);
|
client->addr);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put into the global list */
|
strlcpy(info->type, "smsc47m192", I2C_NAME_SIZE);
|
||||||
strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE);
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int smsc47m192_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct smsc47m192_data *data;
|
||||||
|
int config;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct smsc47m192_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
data->vrm = vid_which_vrm();
|
data->vrm = vid_which_vrm();
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Initialize the SMSC47M192 chip */
|
/* Initialize the SMSC47M192 chip */
|
||||||
smsc47m192_init_client(client);
|
smsc47m192_init_client(client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
/* Pin 110 is either in4 (+12V) or VID4 */
|
/* Pin 110 is either in4 (+12V) or VID4 */
|
||||||
config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
|
config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
|
||||||
@ -563,26 +559,20 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
|
|||||||
exit_remove_files:
|
exit_remove_files:
|
||||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
|
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
|
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int smsc47m192_detach_client(struct i2c_client *client)
|
static int smsc47m192_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct smsc47m192_data *data = i2c_get_clientdata(client);
|
struct smsc47m192_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
|
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
|
||||||
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
|
sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -60,7 +60,6 @@ static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
|
|||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct thmc50_data {
|
struct thmc50_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
|
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
@ -77,17 +76,31 @@ struct thmc50_data {
|
|||||||
u8 alarms;
|
u8 alarms;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int thmc50_attach_adapter(struct i2c_adapter *adapter);
|
static int thmc50_detect(struct i2c_client *client, int kind,
|
||||||
static int thmc50_detach_client(struct i2c_client *client);
|
struct i2c_board_info *info);
|
||||||
|
static int thmc50_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id);
|
||||||
|
static int thmc50_remove(struct i2c_client *client);
|
||||||
static void thmc50_init_client(struct i2c_client *client);
|
static void thmc50_init_client(struct i2c_client *client);
|
||||||
static struct thmc50_data *thmc50_update_device(struct device *dev);
|
static struct thmc50_data *thmc50_update_device(struct device *dev);
|
||||||
|
|
||||||
|
static const struct i2c_device_id thmc50_id[] = {
|
||||||
|
{ "adm1022", adm1022 },
|
||||||
|
{ "thmc50", thmc50 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, thmc50_id);
|
||||||
|
|
||||||
static struct i2c_driver thmc50_driver = {
|
static struct i2c_driver thmc50_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "thmc50",
|
.name = "thmc50",
|
||||||
},
|
},
|
||||||
.attach_adapter = thmc50_attach_adapter,
|
.probe = thmc50_probe,
|
||||||
.detach_client = thmc50_detach_client,
|
.remove = thmc50_remove,
|
||||||
|
.id_table = thmc50_id,
|
||||||
|
.detect = thmc50_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t show_analog_out(struct device *dev,
|
static ssize_t show_analog_out(struct device *dev,
|
||||||
@ -250,39 +263,23 @@ static const struct attribute_group temp3_group = {
|
|||||||
.attrs = temp3_attributes,
|
.attrs = temp3_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int thmc50_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
unsigned company;
|
unsigned company;
|
||||||
unsigned revision;
|
unsigned revision;
|
||||||
unsigned config;
|
unsigned config;
|
||||||
struct i2c_client *client;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct thmc50_data *data;
|
|
||||||
struct device *dev;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
const char *type_name;
|
const char *type_name;
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
pr_debug("thmc50: detect failed, "
|
pr_debug("thmc50: detect failed, "
|
||||||
"smbus byte data not supported!\n");
|
"smbus byte data not supported!\n");
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access thmc50 registers. */
|
|
||||||
if (!(data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL))) {
|
|
||||||
pr_debug("thmc50: detect failed, kzalloc failed!\n");
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &thmc50_driver;
|
|
||||||
dev = &client->dev;
|
|
||||||
|
|
||||||
pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n",
|
pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n",
|
||||||
client->addr, i2c_adapter_id(client->adapter));
|
client->addr, i2c_adapter_id(client->adapter));
|
||||||
|
|
||||||
@ -307,21 +304,22 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
}
|
}
|
||||||
if (err == -ENODEV) {
|
if (err == -ENODEV) {
|
||||||
pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
|
pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
|
||||||
goto exit_free;
|
return err;
|
||||||
}
|
}
|
||||||
data->type = kind;
|
|
||||||
|
|
||||||
if (kind == adm1022) {
|
if (kind == adm1022) {
|
||||||
int id = i2c_adapter_id(client->adapter);
|
int id = i2c_adapter_id(client->adapter);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
type_name = "adm1022";
|
type_name = "adm1022";
|
||||||
data->has_temp3 = (config >> 7) & 1; /* config MSB */
|
|
||||||
for (i = 0; i + 1 < adm1022_temp3_num; i += 2)
|
for (i = 0; i + 1 < adm1022_temp3_num; i += 2)
|
||||||
if (adm1022_temp3[i] == id &&
|
if (adm1022_temp3[i] == id &&
|
||||||
adm1022_temp3[i + 1] == address) {
|
adm1022_temp3[i + 1] == client->addr) {
|
||||||
/* enable 2nd remote temp */
|
/* enable 2nd remote temp */
|
||||||
data->has_temp3 = 1;
|
config |= (1 << 7);
|
||||||
|
i2c_smbus_write_byte_data(client,
|
||||||
|
THMC50_REG_CONF,
|
||||||
|
config);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -330,19 +328,33 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
|
pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
|
||||||
type_name, (revision >> 4) - 0xc, revision & 0xf);
|
type_name, (revision >> 4) - 0xc, revision & 0xf);
|
||||||
|
|
||||||
/* Fill in the remaining client fields & put it into the global list */
|
strlcpy(info->type, type_name, I2C_NAME_SIZE);
|
||||||
strlcpy(client->name, type_name, I2C_NAME_SIZE);
|
|
||||||
mutex_init(&data->update_lock);
|
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
return 0;
|
||||||
if ((err = i2c_attach_client(client)))
|
}
|
||||||
goto exit_free;
|
|
||||||
|
static int thmc50_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct thmc50_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
pr_debug("thmc50: detect failed, kzalloc failed!\n");
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
data->type = id->driver_data;
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
thmc50_init_client(client);
|
thmc50_init_client(client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
if ((err = sysfs_create_group(&client->dev.kobj, &thmc50_group)))
|
if ((err = sysfs_create_group(&client->dev.kobj, &thmc50_group)))
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
/* Register ADM1022 sysfs hooks */
|
/* Register ADM1022 sysfs hooks */
|
||||||
if (data->has_temp3)
|
if (data->has_temp3)
|
||||||
@ -364,34 +376,21 @@ exit_remove_sysfs:
|
|||||||
sysfs_remove_group(&client->dev.kobj, &temp3_group);
|
sysfs_remove_group(&client->dev.kobj, &temp3_group);
|
||||||
exit_remove_sysfs_thmc50:
|
exit_remove_sysfs_thmc50:
|
||||||
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
|
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int thmc50_attach_adapter(struct i2c_adapter *adapter)
|
static int thmc50_remove(struct i2c_client *client)
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, thmc50_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int thmc50_detach_client(struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
struct thmc50_data *data = i2c_get_clientdata(client);
|
struct thmc50_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
|
sysfs_remove_group(&client->dev.kobj, &thmc50_group);
|
||||||
if (data->has_temp3)
|
if (data->has_temp3)
|
||||||
sysfs_remove_group(&client->dev.kobj, &temp3_group);
|
sysfs_remove_group(&client->dev.kobj, &temp3_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -412,8 +411,8 @@ static void thmc50_init_client(struct i2c_client *client)
|
|||||||
}
|
}
|
||||||
config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
|
config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
|
||||||
config |= 0x1; /* start the chip if it is in standby mode */
|
config |= 0x1; /* start the chip if it is in standby mode */
|
||||||
if (data->has_temp3)
|
if (data->type == adm1022 && (config & (1 << 7)))
|
||||||
config |= 0x80; /* enable 2nd remote temp */
|
data->has_temp3 = 1;
|
||||||
i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
|
i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +247,6 @@ static u8 div_to_reg(int nr, long val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct w83791d_data {
|
struct w83791d_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
|
|
||||||
@ -286,9 +285,11 @@ struct w83791d_data {
|
|||||||
u8 vrm; /* hwmon-vid */
|
u8 vrm; /* hwmon-vid */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int w83791d_attach_adapter(struct i2c_adapter *adapter);
|
static int w83791d_probe(struct i2c_client *client,
|
||||||
static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int w83791d_detach_client(struct i2c_client *client);
|
static int w83791d_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int w83791d_remove(struct i2c_client *client);
|
||||||
|
|
||||||
static int w83791d_read(struct i2c_client *client, u8 register);
|
static int w83791d_read(struct i2c_client *client, u8 register);
|
||||||
static int w83791d_write(struct i2c_client *client, u8 register, u8 value);
|
static int w83791d_write(struct i2c_client *client, u8 register, u8 value);
|
||||||
@ -300,12 +301,22 @@ static void w83791d_print_debug(struct w83791d_data *data, struct device *dev);
|
|||||||
|
|
||||||
static void w83791d_init_client(struct i2c_client *client);
|
static void w83791d_init_client(struct i2c_client *client);
|
||||||
|
|
||||||
|
static const struct i2c_device_id w83791d_id[] = {
|
||||||
|
{ "w83791d", w83791d },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, w83791d_id);
|
||||||
|
|
||||||
static struct i2c_driver w83791d_driver = {
|
static struct i2c_driver w83791d_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "w83791d",
|
.name = "w83791d",
|
||||||
},
|
},
|
||||||
.attach_adapter = w83791d_attach_adapter,
|
.probe = w83791d_probe,
|
||||||
.detach_client = w83791d_detach_client,
|
.remove = w83791d_remove,
|
||||||
|
.id_table = w83791d_id,
|
||||||
|
.detect = w83791d_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* following are the sysfs callback functions */
|
/* following are the sysfs callback functions */
|
||||||
@ -905,49 +916,12 @@ static const struct attribute_group w83791d_group = {
|
|||||||
.attrs = w83791d_attributes,
|
.attrs = w83791d_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This function is called when:
|
|
||||||
* w83791d_driver is inserted (when this module is loaded), for each
|
static int w83791d_detect_subclients(struct i2c_client *client)
|
||||||
available adapter
|
|
||||||
* when a new adapter is inserted (and w83791d_driver is still present) */
|
|
||||||
static int w83791d_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, w83791d_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int w83791d_create_subclient(struct i2c_adapter *adapter,
|
|
||||||
struct i2c_client *client, int addr,
|
|
||||||
struct i2c_client **sub_cli)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct i2c_client *sub_client;
|
|
||||||
|
|
||||||
(*sub_cli) = sub_client =
|
|
||||||
kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
|
||||||
if (!(sub_client)) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
sub_client->addr = 0x48 + addr;
|
|
||||||
i2c_set_clientdata(sub_client, NULL);
|
|
||||||
sub_client->adapter = adapter;
|
|
||||||
sub_client->driver = &w83791d_driver;
|
|
||||||
strlcpy(sub_client->name, "w83791d subclient", I2C_NAME_SIZE);
|
|
||||||
if ((err = i2c_attach_client(sub_client))) {
|
|
||||||
dev_err(&client->dev, "subclient registration "
|
|
||||||
"at address 0x%x failed\n", sub_client->addr);
|
|
||||||
kfree(sub_client);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
|
|
||||||
int kind, struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct w83791d_data *data = i2c_get_clientdata(client);
|
struct w83791d_data *data = i2c_get_clientdata(client);
|
||||||
|
int address = client->addr;
|
||||||
int i, id, err;
|
int i, id, err;
|
||||||
u8 val;
|
u8 val;
|
||||||
|
|
||||||
@ -971,10 +945,7 @@ static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
|
|||||||
|
|
||||||
val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
|
val = w83791d_read(client, W83791D_REG_I2C_SUBADDR);
|
||||||
if (!(val & 0x08)) {
|
if (!(val & 0x08)) {
|
||||||
err = w83791d_create_subclient(adapter, client,
|
data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
|
||||||
val & 0x7, &data->lm75[0]);
|
|
||||||
if (err < 0)
|
|
||||||
goto error_sc_0;
|
|
||||||
}
|
}
|
||||||
if (!(val & 0x80)) {
|
if (!(val & 0x80)) {
|
||||||
if ((data->lm75[0] != NULL) &&
|
if ((data->lm75[0] != NULL) &&
|
||||||
@ -986,10 +957,8 @@ static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
|
|||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto error_sc_1;
|
goto error_sc_1;
|
||||||
}
|
}
|
||||||
err = w83791d_create_subclient(adapter, client,
|
data->lm75[1] = i2c_new_dummy(adapter,
|
||||||
(val >> 4) & 0x7, &data->lm75[1]);
|
0x48 + ((val >> 4) & 0x7));
|
||||||
if (err < 0)
|
|
||||||
goto error_sc_1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -997,53 +966,31 @@ static int w83791d_detect_subclients(struct i2c_adapter *adapter, int address,
|
|||||||
/* Undo inits in case of errors */
|
/* Undo inits in case of errors */
|
||||||
|
|
||||||
error_sc_1:
|
error_sc_1:
|
||||||
if (data->lm75[0] != NULL) {
|
if (data->lm75[0] != NULL)
|
||||||
i2c_detach_client(data->lm75[0]);
|
i2c_unregister_device(data->lm75[0]);
|
||||||
kfree(data->lm75[0]);
|
|
||||||
}
|
|
||||||
error_sc_0:
|
error_sc_0:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int w83791d_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct i2c_client *client;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct device *dev;
|
int val1, val2;
|
||||||
struct w83791d_data *data;
|
unsigned short address = client->addr;
|
||||||
int i, val1, val2;
|
|
||||||
int err = 0;
|
|
||||||
const char *client_name = "";
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
goto error0;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access w83791d_{read,write}_value. */
|
|
||||||
if (!(data = kzalloc(sizeof(struct w83791d_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto error0;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
dev = &client->dev;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &w83791d_driver;
|
|
||||||
mutex_init(&data->update_lock);
|
|
||||||
|
|
||||||
/* Now, we do the remaining detection. */
|
|
||||||
|
|
||||||
/* The w83791d may be stuck in some other bank than bank 0. This may
|
/* The w83791d may be stuck in some other bank than bank 0. This may
|
||||||
make reading other information impossible. Specify a force=...
|
make reading other information impossible. Specify a force=...
|
||||||
parameter, and the Winbond will be reset to the right bank. */
|
parameter, and the Winbond will be reset to the right bank. */
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80) {
|
if (w83791d_read(client, W83791D_REG_CONFIG) & 0x80) {
|
||||||
dev_dbg(dev, "Detection failed at step 1\n");
|
return -ENODEV;
|
||||||
goto error1;
|
|
||||||
}
|
}
|
||||||
val1 = w83791d_read(client, W83791D_REG_BANK);
|
val1 = w83791d_read(client, W83791D_REG_BANK);
|
||||||
val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
|
val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
|
||||||
@ -1052,15 +999,13 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
/* yes it is Bank0 */
|
/* yes it is Bank0 */
|
||||||
if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
|
if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
|
||||||
((val1 & 0x80) && (val2 != 0x5c))) {
|
((val1 & 0x80) && (val2 != 0x5c))) {
|
||||||
dev_dbg(dev, "Detection failed at step 2\n");
|
return -ENODEV;
|
||||||
goto error1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* If Winbond chip, address of chip and W83791D_REG_I2C_ADDR
|
/* If Winbond chip, address of chip and W83791D_REG_I2C_ADDR
|
||||||
should match */
|
should match */
|
||||||
if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address) {
|
if (w83791d_read(client, W83791D_REG_I2C_ADDR) != address) {
|
||||||
dev_dbg(dev, "Detection failed at step 3\n");
|
return -ENODEV;
|
||||||
goto error1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1075,30 +1020,33 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
/* get vendor ID */
|
/* get vendor ID */
|
||||||
val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
|
val2 = w83791d_read(client, W83791D_REG_CHIPMAN);
|
||||||
if (val2 != 0x5c) { /* the vendor is NOT Winbond */
|
if (val2 != 0x5c) { /* the vendor is NOT Winbond */
|
||||||
dev_dbg(dev, "Detection failed at step 4\n");
|
return -ENODEV;
|
||||||
goto error1;
|
|
||||||
}
|
}
|
||||||
val1 = w83791d_read(client, W83791D_REG_WCHIPID);
|
val1 = w83791d_read(client, W83791D_REG_WCHIPID);
|
||||||
if (val1 == 0x71) {
|
if (val1 == 0x71) {
|
||||||
kind = w83791d;
|
kind = w83791d;
|
||||||
} else {
|
} else {
|
||||||
if (kind == 0)
|
if (kind == 0)
|
||||||
dev_warn(dev,
|
dev_warn(&adapter->dev,
|
||||||
"w83791d: Ignoring 'force' parameter "
|
"w83791d: Ignoring 'force' parameter "
|
||||||
"for unknown chip at adapter %d, "
|
"for unknown chip at adapter %d, "
|
||||||
"address 0x%02x\n",
|
"address 0x%02x\n",
|
||||||
i2c_adapter_id(adapter), address);
|
i2c_adapter_id(adapter), address);
|
||||||
goto error1;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kind == w83791d) {
|
strlcpy(info->type, "w83791d", I2C_NAME_SIZE);
|
||||||
client_name = "w83791d";
|
|
||||||
} else {
|
return 0;
|
||||||
dev_err(dev, "w83791d: Internal error: unknown kind (%d)?!?\n",
|
}
|
||||||
kind);
|
|
||||||
goto error1;
|
static int w83791d_probe(struct i2c_client *client,
|
||||||
}
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct w83791d_data *data;
|
||||||
|
struct device *dev = &client->dev;
|
||||||
|
int i, val1, err;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
val1 = w83791d_read(client, W83791D_REG_DID_VID4);
|
val1 = w83791d_read(client, W83791D_REG_DID_VID4);
|
||||||
@ -1106,16 +1054,19 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
(val1 >> 5) & 0x07, (val1 >> 1) & 0x0f, val1);
|
(val1 >> 5) & 0x07, (val1 >> 1) & 0x0f, val1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put into the global list */
|
data = kzalloc(sizeof(struct w83791d_data), GFP_KERNEL);
|
||||||
strlcpy(client->name, client_name, I2C_NAME_SIZE);
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto error0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
i2c_set_clientdata(client, data);
|
||||||
if ((err = i2c_attach_client(client)))
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
|
err = w83791d_detect_subclients(client);
|
||||||
|
if (err)
|
||||||
goto error1;
|
goto error1;
|
||||||
|
|
||||||
if ((err = w83791d_detect_subclients(adapter, address, kind, client)))
|
|
||||||
goto error2;
|
|
||||||
|
|
||||||
/* Initialize the chip */
|
/* Initialize the chip */
|
||||||
w83791d_init_client(client);
|
w83791d_init_client(client);
|
||||||
|
|
||||||
@ -1141,43 +1092,29 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
error4:
|
error4:
|
||||||
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
|
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
|
||||||
error3:
|
error3:
|
||||||
if (data->lm75[0] != NULL) {
|
if (data->lm75[0] != NULL)
|
||||||
i2c_detach_client(data->lm75[0]);
|
i2c_unregister_device(data->lm75[0]);
|
||||||
kfree(data->lm75[0]);
|
if (data->lm75[1] != NULL)
|
||||||
}
|
i2c_unregister_device(data->lm75[1]);
|
||||||
if (data->lm75[1] != NULL) {
|
|
||||||
i2c_detach_client(data->lm75[1]);
|
|
||||||
kfree(data->lm75[1]);
|
|
||||||
}
|
|
||||||
error2:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
error1:
|
error1:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
error0:
|
error0:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int w83791d_detach_client(struct i2c_client *client)
|
static int w83791d_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct w83791d_data *data = i2c_get_clientdata(client);
|
struct w83791d_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
/* main client */
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
if (data) {
|
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
|
||||||
sysfs_remove_group(&client->dev.kobj, &w83791d_group);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
if (data->lm75[0] != NULL)
|
||||||
return err;
|
i2c_unregister_device(data->lm75[0]);
|
||||||
|
if (data->lm75[1] != NULL)
|
||||||
/* main client */
|
i2c_unregister_device(data->lm75[1]);
|
||||||
if (data)
|
|
||||||
kfree(data);
|
|
||||||
/* subclient */
|
|
||||||
else
|
|
||||||
kfree(client);
|
|
||||||
|
|
||||||
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,9 +267,7 @@ DIV_TO_REG(long val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct w83792d_data {
|
struct w83792d_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
enum chips type;
|
|
||||||
|
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* !=0 if following fields are valid */
|
char valid; /* !=0 if following fields are valid */
|
||||||
@ -299,9 +297,11 @@ struct w83792d_data {
|
|||||||
u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */
|
u8 sf2_levels[3][4]; /* Smart FanII: Fan1,2,3 duty cycle levels */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int w83792d_attach_adapter(struct i2c_adapter *adapter);
|
static int w83792d_probe(struct i2c_client *client,
|
||||||
static int w83792d_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int w83792d_detach_client(struct i2c_client *client);
|
static int w83792d_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int w83792d_remove(struct i2c_client *client);
|
||||||
static struct w83792d_data *w83792d_update_device(struct device *dev);
|
static struct w83792d_data *w83792d_update_device(struct device *dev);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -310,12 +310,22 @@ static void w83792d_print_debug(struct w83792d_data *data, struct device *dev);
|
|||||||
|
|
||||||
static void w83792d_init_client(struct i2c_client *client);
|
static void w83792d_init_client(struct i2c_client *client);
|
||||||
|
|
||||||
|
static const struct i2c_device_id w83792d_id[] = {
|
||||||
|
{ "w83792d", w83792d },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, w83792d_id);
|
||||||
|
|
||||||
static struct i2c_driver w83792d_driver = {
|
static struct i2c_driver w83792d_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "w83792d",
|
.name = "w83792d",
|
||||||
},
|
},
|
||||||
.attach_adapter = w83792d_attach_adapter,
|
.probe = w83792d_probe,
|
||||||
.detach_client = w83792d_detach_client,
|
.remove = w83792d_remove,
|
||||||
|
.id_table = w83792d_id,
|
||||||
|
.detect = w83792d_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline long in_count_from_reg(int nr, struct w83792d_data *data)
|
static inline long in_count_from_reg(int nr, struct w83792d_data *data)
|
||||||
@ -864,53 +874,14 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called when:
|
|
||||||
* w83792d_driver is inserted (when this module is loaded), for each
|
|
||||||
available adapter
|
|
||||||
* when a new adapter is inserted (and w83792d_driver is still present) */
|
|
||||||
static int
|
|
||||||
w83792d_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, w83792d_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
w83792d_create_subclient(struct i2c_adapter *adapter,
|
w83792d_detect_subclients(struct i2c_client *new_client)
|
||||||
struct i2c_client *new_client, int addr,
|
|
||||||
struct i2c_client **sub_cli)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct i2c_client *sub_client;
|
|
||||||
|
|
||||||
(*sub_cli) = sub_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
|
||||||
if (!(sub_client)) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
sub_client->addr = 0x48 + addr;
|
|
||||||
i2c_set_clientdata(sub_client, NULL);
|
|
||||||
sub_client->adapter = adapter;
|
|
||||||
sub_client->driver = &w83792d_driver;
|
|
||||||
sub_client->flags = 0;
|
|
||||||
strlcpy(sub_client->name, "w83792d subclient", I2C_NAME_SIZE);
|
|
||||||
if ((err = i2c_attach_client(sub_client))) {
|
|
||||||
dev_err(&new_client->dev, "subclient registration "
|
|
||||||
"at address 0x%x failed\n", sub_client->addr);
|
|
||||||
kfree(sub_client);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
|
|
||||||
struct i2c_client *new_client)
|
|
||||||
{
|
{
|
||||||
int i, id, err;
|
int i, id, err;
|
||||||
|
int address = new_client->addr;
|
||||||
u8 val;
|
u8 val;
|
||||||
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
struct w83792d_data *data = i2c_get_clientdata(new_client);
|
struct w83792d_data *data = i2c_get_clientdata(new_client);
|
||||||
|
|
||||||
id = i2c_adapter_id(adapter);
|
id = i2c_adapter_id(adapter);
|
||||||
@ -932,10 +903,7 @@ w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
|
|||||||
|
|
||||||
val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
|
val = w83792d_read_value(new_client, W83792D_REG_I2C_SUBADDR);
|
||||||
if (!(val & 0x08)) {
|
if (!(val & 0x08)) {
|
||||||
err = w83792d_create_subclient(adapter, new_client, val & 0x7,
|
data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (val & 0x7));
|
||||||
&data->lm75[0]);
|
|
||||||
if (err < 0)
|
|
||||||
goto ERROR_SC_0;
|
|
||||||
}
|
}
|
||||||
if (!(val & 0x80)) {
|
if (!(val & 0x80)) {
|
||||||
if ((data->lm75[0] != NULL) &&
|
if ((data->lm75[0] != NULL) &&
|
||||||
@ -945,10 +913,8 @@ w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
|
|||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto ERROR_SC_1;
|
goto ERROR_SC_1;
|
||||||
}
|
}
|
||||||
err = w83792d_create_subclient(adapter, new_client,
|
data->lm75[1] = i2c_new_dummy(adapter,
|
||||||
(val >> 4) & 0x7, &data->lm75[1]);
|
0x48 + ((val >> 4) & 0x7));
|
||||||
if (err < 0)
|
|
||||||
goto ERROR_SC_1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -956,10 +922,8 @@ w83792d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
|
|||||||
/* Undo inits in case of errors */
|
/* Undo inits in case of errors */
|
||||||
|
|
||||||
ERROR_SC_1:
|
ERROR_SC_1:
|
||||||
if (data->lm75[0] != NULL) {
|
if (data->lm75[0] != NULL)
|
||||||
i2c_detach_client(data->lm75[0]);
|
i2c_unregister_device(data->lm75[0]);
|
||||||
kfree(data->lm75[0]);
|
|
||||||
}
|
|
||||||
ERROR_SC_0:
|
ERROR_SC_0:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1294,47 +1258,25 @@ static const struct attribute_group w83792d_group = {
|
|||||||
.attrs = w83792d_attributes,
|
.attrs = w83792d_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
static int
|
static int
|
||||||
w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
|
w83792d_detect(struct i2c_client *client, int kind, struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
int i = 0, val1 = 0, val2;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct i2c_client *client;
|
int val1, val2;
|
||||||
struct device *dev;
|
unsigned short address = client->addr;
|
||||||
struct w83792d_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *client_name = "";
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
goto ERROR0;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access w83792d_{read,write}_value. */
|
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct w83792d_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto ERROR0;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
dev = &client->dev;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &w83792d_driver;
|
|
||||||
client->flags = 0;
|
|
||||||
|
|
||||||
/* Now, we do the remaining detection. */
|
|
||||||
|
|
||||||
/* The w83792d may be stuck in some other bank than bank 0. This may
|
/* The w83792d may be stuck in some other bank than bank 0. This may
|
||||||
make reading other information impossible. Specify a force=... or
|
make reading other information impossible. Specify a force=... or
|
||||||
force_*=... parameter, and the Winbond will be reset to the right
|
force_*=... parameter, and the Winbond will be reset to the right
|
||||||
bank. */
|
bank. */
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80) {
|
if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80) {
|
||||||
dev_dbg(dev, "Detection failed at step 1\n");
|
return -ENODEV;
|
||||||
goto ERROR1;
|
|
||||||
}
|
}
|
||||||
val1 = w83792d_read_value(client, W83792D_REG_BANK);
|
val1 = w83792d_read_value(client, W83792D_REG_BANK);
|
||||||
val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
|
val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
|
||||||
@ -1342,16 +1284,14 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
if (!(val1 & 0x07)) { /* is Bank0 */
|
if (!(val1 & 0x07)) { /* is Bank0 */
|
||||||
if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
|
if (((!(val1 & 0x80)) && (val2 != 0xa3)) ||
|
||||||
((val1 & 0x80) && (val2 != 0x5c))) {
|
((val1 & 0x80) && (val2 != 0x5c))) {
|
||||||
dev_dbg(dev, "Detection failed at step 2\n");
|
return -ENODEV;
|
||||||
goto ERROR1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
|
/* If Winbond chip, address of chip and W83792D_REG_I2C_ADDR
|
||||||
should match */
|
should match */
|
||||||
if (w83792d_read_value(client,
|
if (w83792d_read_value(client,
|
||||||
W83792D_REG_I2C_ADDR) != address) {
|
W83792D_REG_I2C_ADDR) != address) {
|
||||||
dev_dbg(dev, "Detection failed at step 3\n");
|
return -ENODEV;
|
||||||
goto ERROR1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1367,45 +1307,48 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
/* get vendor ID */
|
/* get vendor ID */
|
||||||
val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
|
val2 = w83792d_read_value(client, W83792D_REG_CHIPMAN);
|
||||||
if (val2 != 0x5c) { /* the vendor is NOT Winbond */
|
if (val2 != 0x5c) { /* the vendor is NOT Winbond */
|
||||||
goto ERROR1;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
val1 = w83792d_read_value(client, W83792D_REG_WCHIPID);
|
val1 = w83792d_read_value(client, W83792D_REG_WCHIPID);
|
||||||
if (val1 == 0x7a) {
|
if (val1 == 0x7a) {
|
||||||
kind = w83792d;
|
kind = w83792d;
|
||||||
} else {
|
} else {
|
||||||
if (kind == 0)
|
if (kind == 0)
|
||||||
dev_warn(dev,
|
dev_warn(&adapter->dev,
|
||||||
"w83792d: Ignoring 'force' parameter for"
|
"w83792d: Ignoring 'force' parameter for"
|
||||||
" unknown chip at adapter %d, address"
|
" unknown chip at adapter %d, address"
|
||||||
" 0x%02x\n", i2c_adapter_id(adapter),
|
" 0x%02x\n", i2c_adapter_id(adapter),
|
||||||
address);
|
address);
|
||||||
goto ERROR1;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kind == w83792d) {
|
strlcpy(info->type, "w83792d", I2C_NAME_SIZE);
|
||||||
client_name = "w83792d";
|
|
||||||
} else {
|
return 0;
|
||||||
dev_err(dev, "w83792d: Internal error: unknown kind (%d)?!?\n",
|
}
|
||||||
kind);
|
|
||||||
goto ERROR1;
|
static int
|
||||||
|
w83792d_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct w83792d_data *data;
|
||||||
|
struct device *dev = &client->dev;
|
||||||
|
int i, val1, err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct w83792d_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto ERROR0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put into the global list */
|
i2c_set_clientdata(client, data);
|
||||||
strlcpy(client->name, client_name, I2C_NAME_SIZE);
|
|
||||||
data->type = kind;
|
|
||||||
|
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
err = w83792d_detect_subclients(client);
|
||||||
if ((err = i2c_attach_client(client)))
|
if (err)
|
||||||
goto ERROR1;
|
goto ERROR1;
|
||||||
|
|
||||||
if ((err = w83792d_detect_subclients(adapter, address,
|
|
||||||
kind, client)))
|
|
||||||
goto ERROR2;
|
|
||||||
|
|
||||||
/* Initialize the chip */
|
/* Initialize the chip */
|
||||||
w83792d_init_client(client);
|
w83792d_init_client(client);
|
||||||
|
|
||||||
@ -1457,16 +1400,10 @@ exit_remove_files:
|
|||||||
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
|
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
|
||||||
sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
|
sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
|
||||||
ERROR3:
|
ERROR3:
|
||||||
if (data->lm75[0] != NULL) {
|
if (data->lm75[0] != NULL)
|
||||||
i2c_detach_client(data->lm75[0]);
|
i2c_unregister_device(data->lm75[0]);
|
||||||
kfree(data->lm75[0]);
|
if (data->lm75[1] != NULL)
|
||||||
}
|
i2c_unregister_device(data->lm75[1]);
|
||||||
if (data->lm75[1] != NULL) {
|
|
||||||
i2c_detach_client(data->lm75[1]);
|
|
||||||
kfree(data->lm75[1]);
|
|
||||||
}
|
|
||||||
ERROR2:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
ERROR1:
|
ERROR1:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
ERROR0:
|
ERROR0:
|
||||||
@ -1474,30 +1411,23 @@ ERROR0:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
w83792d_detach_client(struct i2c_client *client)
|
w83792d_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct w83792d_data *data = i2c_get_clientdata(client);
|
struct w83792d_data *data = i2c_get_clientdata(client);
|
||||||
int err, i;
|
int i;
|
||||||
|
|
||||||
/* main client */
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
if (data) {
|
sysfs_remove_group(&client->dev.kobj, &w83792d_group);
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
|
||||||
sysfs_remove_group(&client->dev.kobj, &w83792d_group);
|
sysfs_remove_group(&client->dev.kobj,
|
||||||
for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
|
&w83792d_group_fan[i]);
|
||||||
sysfs_remove_group(&client->dev.kobj,
|
|
||||||
&w83792d_group_fan[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
if (data->lm75[0] != NULL)
|
||||||
return err;
|
i2c_unregister_device(data->lm75[0]);
|
||||||
|
if (data->lm75[1] != NULL)
|
||||||
/* main client */
|
i2c_unregister_device(data->lm75[1]);
|
||||||
if (data)
|
|
||||||
kfree(data);
|
|
||||||
/* subclient */
|
|
||||||
else
|
|
||||||
kfree(client);
|
|
||||||
|
|
||||||
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +179,6 @@ static inline s8 TEMP_TO_REG(long val, s8 min, s8 max)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct w83793_data {
|
struct w83793_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct i2c_client *lm75[2];
|
struct i2c_client *lm75[2];
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
@ -226,19 +225,31 @@ struct w83793_data {
|
|||||||
|
|
||||||
static u8 w83793_read_value(struct i2c_client *client, u16 reg);
|
static u8 w83793_read_value(struct i2c_client *client, u16 reg);
|
||||||
static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value);
|
static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value);
|
||||||
static int w83793_attach_adapter(struct i2c_adapter *adapter);
|
static int w83793_probe(struct i2c_client *client,
|
||||||
static int w83793_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int w83793_detach_client(struct i2c_client *client);
|
static int w83793_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int w83793_remove(struct i2c_client *client);
|
||||||
static void w83793_init_client(struct i2c_client *client);
|
static void w83793_init_client(struct i2c_client *client);
|
||||||
static void w83793_update_nonvolatile(struct device *dev);
|
static void w83793_update_nonvolatile(struct device *dev);
|
||||||
static struct w83793_data *w83793_update_device(struct device *dev);
|
static struct w83793_data *w83793_update_device(struct device *dev);
|
||||||
|
|
||||||
|
static const struct i2c_device_id w83793_id[] = {
|
||||||
|
{ "w83793", w83793 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, w83793_id);
|
||||||
|
|
||||||
static struct i2c_driver w83793_driver = {
|
static struct i2c_driver w83793_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "w83793",
|
.name = "w83793",
|
||||||
},
|
},
|
||||||
.attach_adapter = w83793_attach_adapter,
|
.probe = w83793_probe,
|
||||||
.detach_client = w83793_detach_client,
|
.remove = w83793_remove,
|
||||||
|
.id_table = w83793_id,
|
||||||
|
.detect = w83793_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
@ -1053,89 +1064,51 @@ static void w83793_init_client(struct i2c_client *client)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int w83793_attach_adapter(struct i2c_adapter *adapter)
|
static int w83793_remove(struct i2c_client *client)
|
||||||
{
|
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, w83793_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int w83793_detach_client(struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
struct w83793_data *data = i2c_get_clientdata(client);
|
struct w83793_data *data = i2c_get_clientdata(client);
|
||||||
struct device *dev = &client->dev;
|
struct device *dev = &client->dev;
|
||||||
int err, i;
|
int i;
|
||||||
|
|
||||||
/* main client */
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
if (data) {
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
|
for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++)
|
||||||
device_remove_file(dev,
|
device_remove_file(dev,
|
||||||
&w83793_sensor_attr_2[i].dev_attr);
|
&w83793_sensor_attr_2[i].dev_attr);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
|
for (i = 0; i < ARRAY_SIZE(sda_single_files); i++)
|
||||||
device_remove_file(dev, &sda_single_files[i].dev_attr);
|
device_remove_file(dev, &sda_single_files[i].dev_attr);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
|
for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
|
||||||
device_remove_file(dev, &w83793_vid[i].dev_attr);
|
device_remove_file(dev, &w83793_vid[i].dev_attr);
|
||||||
device_remove_file(dev, &dev_attr_vrm);
|
device_remove_file(dev, &dev_attr_vrm);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
|
for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
|
||||||
device_remove_file(dev, &w83793_left_fan[i].dev_attr);
|
device_remove_file(dev, &w83793_left_fan[i].dev_attr);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++)
|
for (i = 0; i < ARRAY_SIZE(w83793_left_pwm); i++)
|
||||||
device_remove_file(dev, &w83793_left_pwm[i].dev_attr);
|
device_remove_file(dev, &w83793_left_pwm[i].dev_attr);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
|
for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
|
||||||
device_remove_file(dev, &w83793_temp[i].dev_attr);
|
device_remove_file(dev, &w83793_temp[i].dev_attr);
|
||||||
}
|
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
if (data->lm75[0] != NULL)
|
||||||
return err;
|
i2c_unregister_device(data->lm75[0]);
|
||||||
|
if (data->lm75[1] != NULL)
|
||||||
|
i2c_unregister_device(data->lm75[1]);
|
||||||
|
|
||||||
/* main client */
|
kfree(data);
|
||||||
if (data)
|
|
||||||
kfree(data);
|
|
||||||
/* subclient */
|
|
||||||
else
|
|
||||||
kfree(client);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
w83793_create_subclient(struct i2c_adapter *adapter,
|
w83793_detect_subclients(struct i2c_client *client)
|
||||||
struct i2c_client *client, int addr,
|
|
||||||
struct i2c_client **sub_cli)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
struct i2c_client *sub_client;
|
|
||||||
|
|
||||||
(*sub_cli) = sub_client =
|
|
||||||
kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
|
|
||||||
if (!(sub_client)) {
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
sub_client->addr = 0x48 + addr;
|
|
||||||
i2c_set_clientdata(sub_client, NULL);
|
|
||||||
sub_client->adapter = adapter;
|
|
||||||
sub_client->driver = &w83793_driver;
|
|
||||||
strlcpy(sub_client->name, "w83793 subclient", I2C_NAME_SIZE);
|
|
||||||
if ((err = i2c_attach_client(sub_client))) {
|
|
||||||
dev_err(&client->dev, "subclient registration "
|
|
||||||
"at address 0x%x failed\n", sub_client->addr);
|
|
||||||
kfree(sub_client);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
w83793_detect_subclients(struct i2c_adapter *adapter, int address,
|
|
||||||
int kind, struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
int i, id, err;
|
int i, id, err;
|
||||||
|
int address = client->addr;
|
||||||
u8 tmp;
|
u8 tmp;
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct w83793_data *data = i2c_get_clientdata(client);
|
struct w83793_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
id = i2c_adapter_id(adapter);
|
id = i2c_adapter_id(adapter);
|
||||||
@ -1158,11 +1131,7 @@ w83793_detect_subclients(struct i2c_adapter *adapter, int address,
|
|||||||
|
|
||||||
tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
|
tmp = w83793_read_value(client, W83793_REG_I2C_SUBADDR);
|
||||||
if (!(tmp & 0x08)) {
|
if (!(tmp & 0x08)) {
|
||||||
err =
|
data->lm75[0] = i2c_new_dummy(adapter, 0x48 + (tmp & 0x7));
|
||||||
w83793_create_subclient(adapter, client, tmp & 0x7,
|
|
||||||
&data->lm75[0]);
|
|
||||||
if (err < 0)
|
|
||||||
goto ERROR_SC_0;
|
|
||||||
}
|
}
|
||||||
if (!(tmp & 0x80)) {
|
if (!(tmp & 0x80)) {
|
||||||
if ((data->lm75[0] != NULL)
|
if ((data->lm75[0] != NULL)
|
||||||
@ -1173,10 +1142,8 @@ w83793_detect_subclients(struct i2c_adapter *adapter, int address,
|
|||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto ERROR_SC_1;
|
goto ERROR_SC_1;
|
||||||
}
|
}
|
||||||
err = w83793_create_subclient(adapter, client,
|
data->lm75[1] = i2c_new_dummy(adapter,
|
||||||
(tmp >> 4) & 0x7, &data->lm75[1]);
|
0x48 + ((tmp >> 4) & 0x7));
|
||||||
if (err < 0)
|
|
||||||
goto ERROR_SC_1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1184,69 +1151,44 @@ w83793_detect_subclients(struct i2c_adapter *adapter, int address,
|
|||||||
/* Undo inits in case of errors */
|
/* Undo inits in case of errors */
|
||||||
|
|
||||||
ERROR_SC_1:
|
ERROR_SC_1:
|
||||||
if (data->lm75[0] != NULL) {
|
if (data->lm75[0] != NULL)
|
||||||
i2c_detach_client(data->lm75[0]);
|
i2c_unregister_device(data->lm75[0]);
|
||||||
kfree(data->lm75[0]);
|
|
||||||
}
|
|
||||||
ERROR_SC_0:
|
ERROR_SC_0:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int w83793_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
int i;
|
u8 tmp, bank;
|
||||||
u8 tmp, val;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct i2c_client *client;
|
unsigned short address = client->addr;
|
||||||
struct device *dev;
|
|
||||||
struct w83793_data *data;
|
|
||||||
int files_fan = ARRAY_SIZE(w83793_left_fan) / 7;
|
|
||||||
int files_pwm = ARRAY_SIZE(w83793_left_pwm) / 5;
|
|
||||||
int files_temp = ARRAY_SIZE(w83793_temp) / 6;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access w83793_{read,write}_value. */
|
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct w83793_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
dev = &client->dev;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &w83793_driver;
|
|
||||||
|
|
||||||
data->bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
|
|
||||||
|
|
||||||
/* Now, we do the remaining detection. */
|
|
||||||
if (kind < 0) {
|
if (kind < 0) {
|
||||||
tmp = data->bank & 0x80 ? 0x5c : 0xa3;
|
tmp = bank & 0x80 ? 0x5c : 0xa3;
|
||||||
/* Check Winbond vendor ID */
|
/* Check Winbond vendor ID */
|
||||||
if (tmp != i2c_smbus_read_byte_data(client,
|
if (tmp != i2c_smbus_read_byte_data(client,
|
||||||
W83793_REG_VENDORID)) {
|
W83793_REG_VENDORID)) {
|
||||||
pr_debug("w83793: Detection failed at check "
|
pr_debug("w83793: Detection failed at check "
|
||||||
"vendor id\n");
|
"vendor id\n");
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto free_mem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If Winbond chip, address of chip and W83793_REG_I2C_ADDR
|
/* If Winbond chip, address of chip and W83793_REG_I2C_ADDR
|
||||||
should match */
|
should match */
|
||||||
if ((data->bank & 0x07) == 0
|
if ((bank & 0x07) == 0
|
||||||
&& i2c_smbus_read_byte_data(client, W83793_REG_I2C_ADDR) !=
|
&& i2c_smbus_read_byte_data(client, W83793_REG_I2C_ADDR) !=
|
||||||
(address << 1)) {
|
(address << 1)) {
|
||||||
pr_debug("w83793: Detection failed at check "
|
pr_debug("w83793: Detection failed at check "
|
||||||
"i2c addr\n");
|
"i2c addr\n");
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto free_mem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1255,30 +1197,47 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
Winbond. Determine the chip type now */
|
Winbond. Determine the chip type now */
|
||||||
|
|
||||||
if (kind <= 0) {
|
if (kind <= 0) {
|
||||||
if (0x7b == w83793_read_value(client, W83793_REG_CHIPID)) {
|
if (0x7b == i2c_smbus_read_byte_data(client,
|
||||||
|
W83793_REG_CHIPID)) {
|
||||||
kind = w83793;
|
kind = w83793;
|
||||||
} else {
|
} else {
|
||||||
if (kind == 0)
|
if (kind == 0)
|
||||||
dev_warn(&adapter->dev, "w83793: Ignoring "
|
dev_warn(&adapter->dev, "w83793: Ignoring "
|
||||||
"'force' parameter for unknown chip "
|
"'force' parameter for unknown chip "
|
||||||
"at address 0x%02x\n", address);
|
"at address 0x%02x\n", address);
|
||||||
err = -ENODEV;
|
return -ENODEV;
|
||||||
goto free_mem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put into the global list */
|
strlcpy(info->type, "w83793", I2C_NAME_SIZE);
|
||||||
strlcpy(client->name, "w83793", I2C_NAME_SIZE);
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int w83793_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct device *dev = &client->dev;
|
||||||
|
struct w83793_data *data;
|
||||||
|
int i, tmp, val, err;
|
||||||
|
int files_fan = ARRAY_SIZE(w83793_left_fan) / 7;
|
||||||
|
int files_pwm = ARRAY_SIZE(w83793_left_pwm) / 5;
|
||||||
|
int files_temp = ARRAY_SIZE(w83793_temp) / 6;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct w83793_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
data->bank = i2c_smbus_read_byte_data(client, W83793_REG_BANKSEL);
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
err = w83793_detect_subclients(client);
|
||||||
if ((err = i2c_attach_client(client)))
|
if (err)
|
||||||
goto free_mem;
|
goto free_mem;
|
||||||
|
|
||||||
if ((err = w83793_detect_subclients(adapter, address, kind, client)))
|
|
||||||
goto detach_client;
|
|
||||||
|
|
||||||
/* Initialize the chip */
|
/* Initialize the chip */
|
||||||
w83793_init_client(client);
|
w83793_init_client(client);
|
||||||
|
|
||||||
@ -1459,16 +1418,10 @@ exit_remove:
|
|||||||
for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
|
for (i = 0; i < ARRAY_SIZE(w83793_temp); i++)
|
||||||
device_remove_file(dev, &w83793_temp[i].dev_attr);
|
device_remove_file(dev, &w83793_temp[i].dev_attr);
|
||||||
|
|
||||||
if (data->lm75[0] != NULL) {
|
if (data->lm75[0] != NULL)
|
||||||
i2c_detach_client(data->lm75[0]);
|
i2c_unregister_device(data->lm75[0]);
|
||||||
kfree(data->lm75[0]);
|
if (data->lm75[1] != NULL)
|
||||||
}
|
i2c_unregister_device(data->lm75[1]);
|
||||||
if (data->lm75[1] != NULL) {
|
|
||||||
i2c_detach_client(data->lm75[1]);
|
|
||||||
kfree(data->lm75[1]);
|
|
||||||
}
|
|
||||||
detach_client:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
free_mem:
|
free_mem:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
|
@ -81,10 +81,11 @@ I2C_CLIENT_INSMOD_1(w83l785ts);
|
|||||||
* Functions declaration
|
* Functions declaration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int w83l785ts_attach_adapter(struct i2c_adapter *adapter);
|
static int w83l785ts_probe(struct i2c_client *client,
|
||||||
static int w83l785ts_detect(struct i2c_adapter *adapter, int address,
|
const struct i2c_device_id *id);
|
||||||
int kind);
|
static int w83l785ts_detect(struct i2c_client *client, int kind,
|
||||||
static int w83l785ts_detach_client(struct i2c_client *client);
|
struct i2c_board_info *info);
|
||||||
|
static int w83l785ts_remove(struct i2c_client *client);
|
||||||
static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval);
|
static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval);
|
||||||
static struct w83l785ts_data *w83l785ts_update_device(struct device *dev);
|
static struct w83l785ts_data *w83l785ts_update_device(struct device *dev);
|
||||||
|
|
||||||
@ -92,12 +93,22 @@ static struct w83l785ts_data *w83l785ts_update_device(struct device *dev);
|
|||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const struct i2c_device_id w83l785ts_id[] = {
|
||||||
|
{ "w83l785ts", w83l785ts },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, w83l785ts_id);
|
||||||
|
|
||||||
static struct i2c_driver w83l785ts_driver = {
|
static struct i2c_driver w83l785ts_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "w83l785ts",
|
.name = "w83l785ts",
|
||||||
},
|
},
|
||||||
.attach_adapter = w83l785ts_attach_adapter,
|
.probe = w83l785ts_probe,
|
||||||
.detach_client = w83l785ts_detach_client,
|
.remove = w83l785ts_remove,
|
||||||
|
.id_table = w83l785ts_id,
|
||||||
|
.detect = w83l785ts_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -105,7 +116,6 @@ static struct i2c_driver w83l785ts_driver = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct w83l785ts_data {
|
struct w83l785ts_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* zero until following fields are valid */
|
char valid; /* zero until following fields are valid */
|
||||||
@ -135,40 +145,14 @@ static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 1);
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int w83l785ts_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int w83l785ts_detect(struct i2c_client *new_client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = new_client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, w83l785ts_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following function does more than just detection. If detection
|
|
||||||
* succeeds, it also registers the new chip.
|
|
||||||
*/
|
|
||||||
static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *new_client;
|
|
||||||
struct w83l785ts_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct w83l785ts_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The common I2C client data is placed right before the
|
|
||||||
* W83L785TS-specific data. */
|
|
||||||
new_client = &data->client;
|
|
||||||
i2c_set_clientdata(new_client, data);
|
|
||||||
new_client->addr = address;
|
|
||||||
new_client->adapter = adapter;
|
|
||||||
new_client->driver = &w83l785ts_driver;
|
|
||||||
new_client->flags = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we do the remaining detection. A negative kind means that
|
* Now we do the remaining detection. A negative kind means that
|
||||||
@ -188,8 +172,8 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
W83L785TS_REG_TYPE, 0) & 0xFC) != 0x00)) {
|
W83L785TS_REG_TYPE, 0) & 0xFC) != 0x00)) {
|
||||||
dev_dbg(&adapter->dev,
|
dev_dbg(&adapter->dev,
|
||||||
"W83L785TS-S detection failed at 0x%02x.\n",
|
"W83L785TS-S detection failed at 0x%02x.\n",
|
||||||
address);
|
new_client->addr);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,22 +198,34 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
dev_info(&adapter->dev,
|
dev_info(&adapter->dev,
|
||||||
"Unsupported chip (man_id=0x%04X, "
|
"Unsupported chip (man_id=0x%04X, "
|
||||||
"chip_id=0x%02X).\n", man_id, chip_id);
|
"chip_id=0x%02X).\n", man_id, chip_id);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can fill in the remaining client fields. */
|
strlcpy(info->type, "w83l785ts", I2C_NAME_SIZE);
|
||||||
strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE);
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int w83l785ts_probe(struct i2c_client *new_client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct w83l785ts_data *data;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct w83l785ts_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(new_client, data);
|
||||||
data->valid = 0;
|
data->valid = 0;
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Default values in case the first read fails (unlikely). */
|
/* Default values in case the first read fails (unlikely). */
|
||||||
data->temp[1] = data->temp[0] = 0;
|
data->temp[1] = data->temp[0] = 0;
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived. */
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the W83L785TS chip
|
* Initialize the W83L785TS chip
|
||||||
* Nothing yet, assume it is already started.
|
* Nothing yet, assume it is already started.
|
||||||
@ -259,25 +255,20 @@ exit_remove:
|
|||||||
&sensor_dev_attr_temp1_input.dev_attr);
|
&sensor_dev_attr_temp1_input.dev_attr);
|
||||||
device_remove_file(&new_client->dev,
|
device_remove_file(&new_client->dev,
|
||||||
&sensor_dev_attr_temp1_max.dev_attr);
|
&sensor_dev_attr_temp1_max.dev_attr);
|
||||||
i2c_detach_client(new_client);
|
|
||||||
exit_free:
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int w83l785ts_detach_client(struct i2c_client *client)
|
static int w83l785ts_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct w83l785ts_data *data = i2c_get_clientdata(client);
|
struct w83l785ts_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
device_remove_file(&client->dev,
|
device_remove_file(&client->dev,
|
||||||
&sensor_dev_attr_temp1_input.dev_attr);
|
&sensor_dev_attr_temp1_input.dev_attr);
|
||||||
device_remove_file(&client->dev,
|
device_remove_file(&client->dev,
|
||||||
&sensor_dev_attr_temp1_max.dev_attr);
|
&sensor_dev_attr_temp1_max.dev_attr);
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
@ -286,6 +277,18 @@ static int w83l785ts_detach_client(struct i2c_client *client)
|
|||||||
static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
|
static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
|
||||||
{
|
{
|
||||||
int value, i;
|
int value, i;
|
||||||
|
struct device *dev;
|
||||||
|
const char *prefix;
|
||||||
|
|
||||||
|
/* We might be called during detection, at which point the client
|
||||||
|
isn't yet fully initialized, so we can't use dev_dbg on it */
|
||||||
|
if (i2c_get_clientdata(client)) {
|
||||||
|
dev = &client->dev;
|
||||||
|
prefix = "";
|
||||||
|
} else {
|
||||||
|
dev = &client->adapter->dev;
|
||||||
|
prefix = "w83l785ts: ";
|
||||||
|
}
|
||||||
|
|
||||||
/* Frequent read errors have been reported on Asus boards, so we
|
/* Frequent read errors have been reported on Asus boards, so we
|
||||||
* retry on read errors. If it still fails (unlikely), return the
|
* retry on read errors. If it still fails (unlikely), return the
|
||||||
@ -293,15 +296,15 @@ static u8 w83l785ts_read_value(struct i2c_client *client, u8 reg, u8 defval)
|
|||||||
for (i = 1; i <= MAX_RETRIES; i++) {
|
for (i = 1; i <= MAX_RETRIES; i++) {
|
||||||
value = i2c_smbus_read_byte_data(client, reg);
|
value = i2c_smbus_read_byte_data(client, reg);
|
||||||
if (value >= 0) {
|
if (value >= 0) {
|
||||||
dev_dbg(&client->dev, "Read 0x%02x from register "
|
dev_dbg(dev, "%sRead 0x%02x from register 0x%02x.\n",
|
||||||
"0x%02x.\n", value, reg);
|
prefix, value, reg);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
dev_dbg(&client->dev, "Read failed, will retry in %d.\n", i);
|
dev_dbg(dev, "%sRead failed, will retry in %d.\n", prefix, i);
|
||||||
msleep(i);
|
msleep(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_err(&client->dev, "Couldn't read value from register 0x%02x.\n",
|
dev_err(dev, "%sCouldn't read value from register 0x%02x.\n", prefix,
|
||||||
reg);
|
reg);
|
||||||
return defval;
|
return defval;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,6 @@ DIV_TO_REG(long val)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct w83l786ng_data {
|
struct w83l786ng_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
char valid; /* !=0 if following fields are valid */
|
char valid; /* !=0 if following fields are valid */
|
||||||
@ -146,18 +145,30 @@ struct w83l786ng_data {
|
|||||||
u8 tolerance[2];
|
u8 tolerance[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int w83l786ng_attach_adapter(struct i2c_adapter *adapter);
|
static int w83l786ng_probe(struct i2c_client *client,
|
||||||
static int w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int w83l786ng_detach_client(struct i2c_client *client);
|
static int w83l786ng_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int w83l786ng_remove(struct i2c_client *client);
|
||||||
static void w83l786ng_init_client(struct i2c_client *client);
|
static void w83l786ng_init_client(struct i2c_client *client);
|
||||||
static struct w83l786ng_data *w83l786ng_update_device(struct device *dev);
|
static struct w83l786ng_data *w83l786ng_update_device(struct device *dev);
|
||||||
|
|
||||||
|
static const struct i2c_device_id w83l786ng_id[] = {
|
||||||
|
{ "w83l786ng", w83l786ng },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, w83l786ng_id);
|
||||||
|
|
||||||
static struct i2c_driver w83l786ng_driver = {
|
static struct i2c_driver w83l786ng_driver = {
|
||||||
|
.class = I2C_CLASS_HWMON,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "w83l786ng",
|
.name = "w83l786ng",
|
||||||
},
|
},
|
||||||
.attach_adapter = w83l786ng_attach_adapter,
|
.probe = w83l786ng_probe,
|
||||||
.detach_client = w83l786ng_detach_client,
|
.remove = w83l786ng_remove,
|
||||||
|
.id_table = w83l786ng_id,
|
||||||
|
.detect = w83l786ng_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static u8
|
static u8
|
||||||
@ -575,42 +586,15 @@ static const struct attribute_group w83l786ng_group = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
w83l786ng_attach_adapter(struct i2c_adapter *adapter)
|
w83l786ng_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & I2C_CLASS_HWMON))
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, w83l786ng_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
struct device *dev;
|
|
||||||
struct w83l786ng_data *data;
|
|
||||||
int i, err = 0;
|
|
||||||
u8 reg_tmp;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet.
|
|
||||||
But it allows us to access w83l786ng_{read,write}_value. */
|
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
dev = &client->dev;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &w83l786ng_driver;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we do the remaining detection. A negative kind means that
|
* Now we do the remaining detection. A negative kind means that
|
||||||
* the driver was loaded with no force parameter (default), so we
|
* the driver was loaded with no force parameter (default), so we
|
||||||
@ -627,8 +611,8 @@ w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
W83L786NG_REG_CONFIG) & 0x80) != 0x00)) {
|
W83L786NG_REG_CONFIG) & 0x80) != 0x00)) {
|
||||||
dev_dbg(&adapter->dev,
|
dev_dbg(&adapter->dev,
|
||||||
"W83L786NG detection failed at 0x%02x.\n",
|
"W83L786NG detection failed at 0x%02x.\n",
|
||||||
address);
|
client->addr);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -651,17 +635,31 @@ w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
dev_info(&adapter->dev,
|
dev_info(&adapter->dev,
|
||||||
"Unsupported chip (man_id=0x%04X, "
|
"Unsupported chip (man_id=0x%04X, "
|
||||||
"chip_id=0x%02X).\n", man_id, chip_id);
|
"chip_id=0x%02X).\n", man_id, chip_id);
|
||||||
goto exit_free;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put into the global list */
|
strlcpy(info->type, "w83l786ng", I2C_NAME_SIZE);
|
||||||
strlcpy(client->name, "w83l786ng", I2C_NAME_SIZE);
|
|
||||||
mutex_init(&data->update_lock);
|
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
return 0;
|
||||||
if ((err = i2c_attach_client(client)))
|
}
|
||||||
goto exit_free;
|
|
||||||
|
static int
|
||||||
|
w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct device *dev = &client->dev;
|
||||||
|
struct w83l786ng_data *data;
|
||||||
|
int i, err = 0;
|
||||||
|
u8 reg_tmp;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Initialize the chip */
|
/* Initialize the chip */
|
||||||
w83l786ng_init_client(client);
|
w83l786ng_init_client(client);
|
||||||
@ -693,25 +691,19 @@ w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
|
|
||||||
exit_remove:
|
exit_remove:
|
||||||
sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
|
sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
w83l786ng_detach_client(struct i2c_client *client)
|
w83l786ng_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
struct w83l786ng_data *data = i2c_get_clientdata(client);
|
||||||
int err;
|
|
||||||
|
|
||||||
hwmon_device_unregister(data->hwmon_dev);
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
|
sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -155,6 +155,16 @@ static int __init amd756_s4882_init(void)
|
|||||||
int i, error;
|
int i, error;
|
||||||
union i2c_smbus_data ioconfig;
|
union i2c_smbus_data ioconfig;
|
||||||
|
|
||||||
|
/* Configure the PCA9556 multiplexer */
|
||||||
|
ioconfig.byte = 0x00; /* All I/O to output mode */
|
||||||
|
error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
|
||||||
|
I2C_SMBUS_BYTE_DATA, &ioconfig);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
|
||||||
|
error = -EIO;
|
||||||
|
goto ERROR0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Unregister physical bus */
|
/* Unregister physical bus */
|
||||||
error = i2c_del_adapter(&amd756_smbus);
|
error = i2c_del_adapter(&amd756_smbus);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -198,22 +208,11 @@ static int __init amd756_s4882_init(void)
|
|||||||
s4882_algo[3].smbus_xfer = amd756_access_virt3;
|
s4882_algo[3].smbus_xfer = amd756_access_virt3;
|
||||||
s4882_algo[4].smbus_xfer = amd756_access_virt4;
|
s4882_algo[4].smbus_xfer = amd756_access_virt4;
|
||||||
|
|
||||||
/* Configure the PCA9556 multiplexer */
|
|
||||||
ioconfig.byte = 0x00; /* All I/O to output mode */
|
|
||||||
error = amd756_smbus.algo->smbus_xfer(&amd756_smbus, 0x18, 0,
|
|
||||||
I2C_SMBUS_WRITE, 0x03,
|
|
||||||
I2C_SMBUS_BYTE_DATA, &ioconfig);
|
|
||||||
if (error) {
|
|
||||||
dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
|
|
||||||
error = -EIO;
|
|
||||||
goto ERROR3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register virtual adapters */
|
/* Register virtual adapters */
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
error = i2c_add_adapter(s4882_adapter+i);
|
error = i2c_add_adapter(s4882_adapter+i);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(&amd756_smbus.dev,
|
printk(KERN_ERR "i2c-amd756-s4882: "
|
||||||
"Virtual adapter %d registration "
|
"Virtual adapter %d registration "
|
||||||
"failed, module not inserted\n", i);
|
"failed, module not inserted\n", i);
|
||||||
for (i--; i >= 0; i--)
|
for (i--; i >= 0; i--)
|
||||||
@ -252,8 +251,8 @@ static void __exit amd756_s4882_exit(void)
|
|||||||
|
|
||||||
/* Restore physical bus */
|
/* Restore physical bus */
|
||||||
if (i2c_add_adapter(&amd756_smbus))
|
if (i2c_add_adapter(&amd756_smbus))
|
||||||
dev_err(&amd756_smbus.dev, "Physical bus restoration "
|
printk(KERN_ERR "i2c-amd756-s4882: "
|
||||||
"failed\n");
|
"Physical bus restoration failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||||
|
@ -150,6 +150,16 @@ static int __init nforce2_s4985_init(void)
|
|||||||
int i, error;
|
int i, error;
|
||||||
union i2c_smbus_data ioconfig;
|
union i2c_smbus_data ioconfig;
|
||||||
|
|
||||||
|
/* Configure the PCA9556 multiplexer */
|
||||||
|
ioconfig.byte = 0x00; /* All I/O to output mode */
|
||||||
|
error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
|
||||||
|
I2C_SMBUS_BYTE_DATA, &ioconfig);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
|
||||||
|
error = -EIO;
|
||||||
|
goto ERROR0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Unregister physical bus */
|
/* Unregister physical bus */
|
||||||
if (!nforce2_smbus)
|
if (!nforce2_smbus)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@ -191,24 +201,13 @@ static int __init nforce2_s4985_init(void)
|
|||||||
s4985_algo[3].smbus_xfer = nforce2_access_virt3;
|
s4985_algo[3].smbus_xfer = nforce2_access_virt3;
|
||||||
s4985_algo[4].smbus_xfer = nforce2_access_virt4;
|
s4985_algo[4].smbus_xfer = nforce2_access_virt4;
|
||||||
|
|
||||||
/* Configure the PCA9556 multiplexer */
|
|
||||||
ioconfig.byte = 0x00; /* All I/O to output mode */
|
|
||||||
error = nforce2_smbus->algo->smbus_xfer(nforce2_smbus, 0x18, 0,
|
|
||||||
I2C_SMBUS_WRITE, 0x03,
|
|
||||||
I2C_SMBUS_BYTE_DATA, &ioconfig);
|
|
||||||
if (error) {
|
|
||||||
dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
|
|
||||||
error = -EIO;
|
|
||||||
goto ERROR3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register virtual adapters */
|
/* Register virtual adapters */
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
error = i2c_add_adapter(s4985_adapter + i);
|
error = i2c_add_adapter(s4985_adapter + i);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(&nforce2_smbus->dev,
|
printk(KERN_ERR "i2c-nforce2-s4985: "
|
||||||
"Virtual adapter %d registration "
|
"Virtual adapter %d registration "
|
||||||
"failed, module not inserted\n", i);
|
"failed, module not inserted\n", i);
|
||||||
for (i--; i >= 0; i--)
|
for (i--; i >= 0; i--)
|
||||||
i2c_del_adapter(s4985_adapter + i);
|
i2c_del_adapter(s4985_adapter + i);
|
||||||
goto ERROR3;
|
goto ERROR3;
|
||||||
@ -245,8 +244,8 @@ static void __exit nforce2_s4985_exit(void)
|
|||||||
|
|
||||||
/* Restore physical bus */
|
/* Restore physical bus */
|
||||||
if (i2c_add_adapter(nforce2_smbus))
|
if (i2c_add_adapter(nforce2_smbus))
|
||||||
dev_err(&nforce2_smbus->dev, "Physical bus restoration "
|
printk(KERN_ERR "i2c-nforce2-s4985: "
|
||||||
"failed\n");
|
"Physical bus restoration failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
|
||||||
|
@ -47,7 +47,6 @@ enum eeprom_nature {
|
|||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct eeprom_data {
|
struct eeprom_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
u8 valid; /* bitfield, bit!=0 if slice is valid */
|
u8 valid; /* bitfield, bit!=0 if slice is valid */
|
||||||
unsigned long last_updated[8]; /* In jiffies, 8 slices */
|
unsigned long last_updated[8]; /* In jiffies, 8 slices */
|
||||||
@ -56,19 +55,6 @@ struct eeprom_data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int eeprom_attach_adapter(struct i2c_adapter *adapter);
|
|
||||||
static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind);
|
|
||||||
static int eeprom_detach_client(struct i2c_client *client);
|
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
|
||||||
static struct i2c_driver eeprom_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "eeprom",
|
|
||||||
},
|
|
||||||
.attach_adapter = eeprom_attach_adapter,
|
|
||||||
.detach_client = eeprom_detach_client,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void eeprom_update_client(struct i2c_client *client, u8 slice)
|
static void eeprom_update_client(struct i2c_client *client, u8 slice)
|
||||||
{
|
{
|
||||||
struct eeprom_data *data = i2c_get_clientdata(client);
|
struct eeprom_data *data = i2c_get_clientdata(client);
|
||||||
@ -148,25 +134,17 @@ static struct bin_attribute eeprom_attr = {
|
|||||||
.read = eeprom_read,
|
.read = eeprom_read,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int eeprom_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int eeprom_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
if (!(adapter->class & (I2C_CLASS_DDC | I2C_CLASS_SPD)))
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
return 0;
|
|
||||||
return i2c_probe(adapter, &addr_data, eeprom_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
|
||||||
static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
struct eeprom_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
/* EDID EEPROMs are often 24C00 EEPROMs, which answer to all
|
/* EDID EEPROMs are often 24C00 EEPROMs, which answer to all
|
||||||
addresses 0x50-0x57, but we only care about 0x50. So decline
|
addresses 0x50-0x57, but we only care about 0x50. So decline
|
||||||
attaching to addresses >= 0x51 on DDC buses */
|
attaching to addresses >= 0x51 on DDC buses */
|
||||||
if (!(adapter->class & I2C_CLASS_SPD) && address >= 0x51)
|
if (!(adapter->class & I2C_CLASS_SPD) && client->addr >= 0x51)
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/* There are four ways we can read the EEPROM data:
|
/* There are four ways we can read the EEPROM data:
|
||||||
(1) I2C block reads (faster, but unsupported by most adapters)
|
(1) I2C block reads (faster, but unsupported by most adapters)
|
||||||
@ -177,32 +155,33 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
because all known adapters support one of the first two. */
|
because all known adapters support one of the first two. */
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)
|
||||||
&& !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
|
&& !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
|
strlcpy(info->type, "eeprom", I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int eeprom_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
|
struct eeprom_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
|
if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
memset(data->data, 0xff, EEPROM_SIZE);
|
memset(data->data, 0xff, EEPROM_SIZE);
|
||||||
i2c_set_clientdata(client, data);
|
i2c_set_clientdata(client, data);
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &eeprom_driver;
|
|
||||||
|
|
||||||
/* Fill in the remaining client fields */
|
|
||||||
strlcpy(client->name, "eeprom", I2C_NAME_SIZE);
|
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
data->nature = UNKNOWN;
|
data->nature = UNKNOWN;
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exit_kfree;
|
|
||||||
|
|
||||||
/* Detect the Vaio nature of EEPROMs.
|
/* Detect the Vaio nature of EEPROMs.
|
||||||
We use the "PCG-" or "VGN-" prefix as the signature. */
|
We use the "PCG-" or "VGN-" prefix as the signature. */
|
||||||
if (address == 0x57
|
if (client->addr == 0x57
|
||||||
&& i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
|
&& i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
|
||||||
char name[4];
|
char name[4];
|
||||||
|
|
||||||
@ -221,33 +200,42 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
/* create the sysfs eeprom file */
|
/* create the sysfs eeprom file */
|
||||||
err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
|
err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
|
||||||
if (err)
|
if (err)
|
||||||
goto exit_detach;
|
goto exit_kfree;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_kfree:
|
exit_kfree:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int eeprom_detach_client(struct i2c_client *client)
|
static int eeprom_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
|
|
||||||
sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
|
sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
|
||||||
|
|
||||||
err = i2c_detach_client(client);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(i2c_get_clientdata(client));
|
kfree(i2c_get_clientdata(client));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id eeprom_id[] = {
|
||||||
|
{ "eeprom", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct i2c_driver eeprom_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "eeprom",
|
||||||
|
},
|
||||||
|
.probe = eeprom_probe,
|
||||||
|
.remove = eeprom_remove,
|
||||||
|
.id_table = eeprom_id,
|
||||||
|
|
||||||
|
.class = I2C_CLASS_DDC | I2C_CLASS_SPD,
|
||||||
|
.detect = eeprom_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init eeprom_init(void)
|
static int __init eeprom_init(void)
|
||||||
{
|
{
|
||||||
return i2c_add_driver(&eeprom_driver);
|
return i2c_add_driver(&eeprom_driver);
|
||||||
|
@ -53,7 +53,7 @@ I2C_CLIENT_INSMOD_1(max6875);
|
|||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct max6875_data {
|
struct max6875_data {
|
||||||
struct i2c_client client;
|
struct i2c_client *fake_client;
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
|
|
||||||
u32 valid;
|
u32 valid;
|
||||||
@ -61,19 +61,6 @@ struct max6875_data {
|
|||||||
unsigned long last_updated[USER_EEPROM_SLICES];
|
unsigned long last_updated[USER_EEPROM_SLICES];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int max6875_attach_adapter(struct i2c_adapter *adapter);
|
|
||||||
static int max6875_detect(struct i2c_adapter *adapter, int address, int kind);
|
|
||||||
static int max6875_detach_client(struct i2c_client *client);
|
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
|
||||||
static struct i2c_driver max6875_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "max6875",
|
|
||||||
},
|
|
||||||
.attach_adapter = max6875_attach_adapter,
|
|
||||||
.detach_client = max6875_detach_client,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void max6875_update_slice(struct i2c_client *client, int slice)
|
static void max6875_update_slice(struct i2c_client *client, int slice)
|
||||||
{
|
{
|
||||||
struct max6875_data *data = i2c_get_clientdata(client);
|
struct max6875_data *data = i2c_get_clientdata(client);
|
||||||
@ -159,96 +146,87 @@ static struct bin_attribute user_eeprom_attr = {
|
|||||||
.read = max6875_read,
|
.read = max6875_read,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int max6875_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int max6875_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
return i2c_probe(adapter, &addr_data, max6875_detect);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
|
||||||
static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *real_client;
|
|
||||||
struct i2c_client *fake_client;
|
|
||||||
struct max6875_data *data;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA
|
||||||
| I2C_FUNC_SMBUS_READ_BYTE))
|
| I2C_FUNC_SMBUS_READ_BYTE))
|
||||||
return 0;
|
return -ENODEV;
|
||||||
|
|
||||||
/* Only check even addresses */
|
/* Only check even addresses */
|
||||||
if (address & 1)
|
if (client->addr & 1)
|
||||||
return 0;
|
return -ENODEV;
|
||||||
|
|
||||||
|
strlcpy(info->type, "max6875", I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max6875_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct max6875_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL)))
|
if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL)))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* A fake client is created on the odd address */
|
/* A fake client is created on the odd address */
|
||||||
if (!(fake_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
|
data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1);
|
||||||
|
if (!data->fake_client) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto exit_kfree1;
|
goto exit_kfree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init real i2c_client */
|
/* Init real i2c_client */
|
||||||
real_client = &data->client;
|
i2c_set_clientdata(client, data);
|
||||||
i2c_set_clientdata(real_client, data);
|
|
||||||
real_client->addr = address;
|
|
||||||
real_client->adapter = adapter;
|
|
||||||
real_client->driver = &max6875_driver;
|
|
||||||
strlcpy(real_client->name, "max6875", I2C_NAME_SIZE);
|
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Init fake client data */
|
err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr);
|
||||||
i2c_set_clientdata(fake_client, NULL);
|
|
||||||
fake_client->addr = address | 1;
|
|
||||||
fake_client->adapter = adapter;
|
|
||||||
fake_client->driver = &max6875_driver;
|
|
||||||
strlcpy(fake_client->name, "max6875 subclient", I2C_NAME_SIZE);
|
|
||||||
|
|
||||||
if ((err = i2c_attach_client(real_client)) != 0)
|
|
||||||
goto exit_kfree2;
|
|
||||||
|
|
||||||
if ((err = i2c_attach_client(fake_client)) != 0)
|
|
||||||
goto exit_detach1;
|
|
||||||
|
|
||||||
err = sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
|
|
||||||
if (err)
|
if (err)
|
||||||
goto exit_detach2;
|
goto exit_remove_fake;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exit_detach2:
|
exit_remove_fake:
|
||||||
i2c_detach_client(fake_client);
|
i2c_unregister_device(data->fake_client);
|
||||||
exit_detach1:
|
exit_kfree:
|
||||||
i2c_detach_client(real_client);
|
|
||||||
exit_kfree2:
|
|
||||||
kfree(fake_client);
|
|
||||||
exit_kfree1:
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Will be called for both the real client and the fake client */
|
static int max6875_remove(struct i2c_client *client)
|
||||||
static int max6875_detach_client(struct i2c_client *client)
|
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
struct max6875_data *data = i2c_get_clientdata(client);
|
struct max6875_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
/* data is NULL for the fake client */
|
i2c_unregister_device(data->fake_client);
|
||||||
if (data)
|
|
||||||
sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
|
|
||||||
|
|
||||||
err = i2c_detach_client(client);
|
sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
|
||||||
if (err)
|
kfree(data);
|
||||||
return err;
|
|
||||||
|
|
||||||
if (data) /* real client */
|
|
||||||
kfree(data);
|
|
||||||
else /* fake client */
|
|
||||||
kfree(client);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id max6875_id[] = {
|
||||||
|
{ "max6875", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct i2c_driver max6875_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "max6875",
|
||||||
|
},
|
||||||
|
.probe = max6875_probe,
|
||||||
|
.remove = max6875_remove,
|
||||||
|
.id_table = max6875_id,
|
||||||
|
|
||||||
|
.detect = max6875_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init max6875_init(void)
|
static int __init max6875_init(void)
|
||||||
{
|
{
|
||||||
return i2c_add_driver(&max6875_driver);
|
return i2c_add_driver(&max6875_driver);
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/hwmon-sysfs.h>
|
#include <linux/hwmon-sysfs.h>
|
||||||
|
|
||||||
/* Addresses to scan */
|
/* Addresses to scan: none, device is not autodetected */
|
||||||
static unsigned short normal_i2c[] = {0x74, 0x75, 0x76, 0x77, I2C_CLIENT_END};
|
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
|
||||||
|
|
||||||
/* Insmod parameters */
|
/* Insmod parameters */
|
||||||
I2C_CLIENT_INSMOD_1(pca9539);
|
I2C_CLIENT_INSMOD_1(pca9539);
|
||||||
@ -32,23 +32,6 @@ enum pca9539_cmd
|
|||||||
PCA9539_DIRECTION_1 = 7,
|
PCA9539_DIRECTION_1 = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pca9539_attach_adapter(struct i2c_adapter *adapter);
|
|
||||||
static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind);
|
|
||||||
static int pca9539_detach_client(struct i2c_client *client);
|
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
|
||||||
static struct i2c_driver pca9539_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "pca9539",
|
|
||||||
},
|
|
||||||
.attach_adapter = pca9539_attach_adapter,
|
|
||||||
.detach_client = pca9539_detach_client,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct pca9539_data {
|
|
||||||
struct i2c_client client;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* following are the sysfs callback functions */
|
/* following are the sysfs callback functions */
|
||||||
static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr,
|
static ssize_t pca9539_show(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
@ -105,77 +88,51 @@ static struct attribute_group pca9539_defattr_group = {
|
|||||||
.attrs = pca9539_attributes,
|
.attrs = pca9539_attributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pca9539_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int pca9539_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
return i2c_probe(adapter, &addr_data, pca9539_detect);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
|
||||||
static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
struct pca9539_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
strlcpy(info->type, "pca9539", I2C_NAME_SIZE);
|
||||||
client structure, even though we cannot fill it completely yet. */
|
|
||||||
if (!(data = kzalloc(sizeof(struct pca9539_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &pca9539_driver;
|
|
||||||
|
|
||||||
if (kind < 0) {
|
|
||||||
/* Detection: the pca9539 only has 8 registers (0-7).
|
|
||||||
A read of 7 should succeed, but a read of 8 should fail. */
|
|
||||||
if ((i2c_smbus_read_byte_data(client, 7) < 0) ||
|
|
||||||
(i2c_smbus_read_byte_data(client, 8) >= 0))
|
|
||||||
goto exit_kfree;
|
|
||||||
}
|
|
||||||
|
|
||||||
strlcpy(client->name, "pca9539", I2C_NAME_SIZE);
|
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exit_kfree;
|
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
|
||||||
err = sysfs_create_group(&client->dev.kobj,
|
|
||||||
&pca9539_defattr_group);
|
|
||||||
if (err)
|
|
||||||
goto exit_detach;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_kfree:
|
|
||||||
kfree(data);
|
|
||||||
exit:
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pca9539_detach_client(struct i2c_client *client)
|
static int pca9539_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
int err;
|
/* Register sysfs hooks */
|
||||||
|
return sysfs_create_group(&client->dev.kobj,
|
||||||
|
&pca9539_defattr_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca9539_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
sysfs_remove_group(&client->dev.kobj, &pca9539_defattr_group);
|
sysfs_remove_group(&client->dev.kobj, &pca9539_defattr_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(i2c_get_clientdata(client));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id pca9539_id[] = {
|
||||||
|
{ "pca9539", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct i2c_driver pca9539_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "pca9539",
|
||||||
|
},
|
||||||
|
.probe = pca9539_probe,
|
||||||
|
.remove = pca9539_remove,
|
||||||
|
.id_table = pca9539_id,
|
||||||
|
|
||||||
|
.detect = pca9539_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init pca9539_init(void)
|
static int __init pca9539_init(void)
|
||||||
{
|
{
|
||||||
return i2c_add_driver(&pca9539_driver);
|
return i2c_add_driver(&pca9539_driver);
|
||||||
|
@ -38,37 +38,19 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
|
||||||
/* Addresses to scan */
|
/* Addresses to scan: none, device can't be detected */
|
||||||
static const unsigned short normal_i2c[] = {
|
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
|
||||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
|
||||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
|
||||||
I2C_CLIENT_END
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Insmod parameters */
|
/* Insmod parameters */
|
||||||
I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
|
I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a);
|
||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct pcf8574_data {
|
struct pcf8574_data {
|
||||||
struct i2c_client client;
|
|
||||||
|
|
||||||
int write; /* Remember last written value */
|
int write; /* Remember last written value */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pcf8574_attach_adapter(struct i2c_adapter *adapter);
|
|
||||||
static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind);
|
|
||||||
static int pcf8574_detach_client(struct i2c_client *client);
|
|
||||||
static void pcf8574_init_client(struct i2c_client *client);
|
static void pcf8574_init_client(struct i2c_client *client);
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
|
||||||
static struct i2c_driver pcf8574_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "pcf8574",
|
|
||||||
},
|
|
||||||
.attach_adapter = pcf8574_attach_adapter,
|
|
||||||
.detach_client = pcf8574_detach_client,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* following are the sysfs callback functions */
|
/* following are the sysfs callback functions */
|
||||||
static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf)
|
static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
@ -119,41 +101,22 @@ static const struct attribute_group pcf8574_attr_group = {
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int pcf8574_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int pcf8574_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
return i2c_probe(adapter, &addr_data, pcf8574_detect);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
}
|
const char *client_name;
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
|
||||||
static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
struct pcf8574_data *data;
|
|
||||||
int err = 0;
|
|
||||||
const char *client_name = "";
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet. */
|
|
||||||
if (!(data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &pcf8574_driver;
|
|
||||||
|
|
||||||
/* Now, we would do the remaining detection. But the PCF8574 is plainly
|
/* Now, we would do the remaining detection. But the PCF8574 is plainly
|
||||||
impossible to detect! Stupid chip. */
|
impossible to detect! Stupid chip. */
|
||||||
|
|
||||||
/* Determine the chip type */
|
/* Determine the chip type */
|
||||||
if (kind <= 0) {
|
if (kind <= 0) {
|
||||||
if (address >= 0x38 && address <= 0x3f)
|
if (client->addr >= 0x38 && client->addr <= 0x3f)
|
||||||
kind = pcf8574a;
|
kind = pcf8574a;
|
||||||
else
|
else
|
||||||
kind = pcf8574;
|
kind = pcf8574;
|
||||||
@ -163,40 +126,43 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
client_name = "pcf8574a";
|
client_name = "pcf8574a";
|
||||||
else
|
else
|
||||||
client_name = "pcf8574";
|
client_name = "pcf8574";
|
||||||
|
strlcpy(info->type, client_name, I2C_NAME_SIZE);
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put it into the global list */
|
return 0;
|
||||||
strlcpy(client->name, client_name, I2C_NAME_SIZE);
|
}
|
||||||
|
|
||||||
|
static int pcf8574_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct pcf8574_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Initialize the PCF8574 chip */
|
/* Initialize the PCF8574 chip */
|
||||||
pcf8574_init_client(client);
|
pcf8574_init_client(client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
err = sysfs_create_group(&client->dev.kobj, &pcf8574_attr_group);
|
err = sysfs_create_group(&client->dev.kobj, &pcf8574_attr_group);
|
||||||
if (err)
|
if (err)
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pcf8574_detach_client(struct i2c_client *client)
|
static int pcf8574_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
|
|
||||||
sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group);
|
sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(i2c_get_clientdata(client));
|
kfree(i2c_get_clientdata(client));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -208,6 +174,24 @@ static void pcf8574_init_client(struct i2c_client *client)
|
|||||||
data->write = -EAGAIN;
|
data->write = -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id pcf8574_id[] = {
|
||||||
|
{ "pcf8574", 0 },
|
||||||
|
{ "pcf8574a", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct i2c_driver pcf8574_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "pcf8574",
|
||||||
|
},
|
||||||
|
.probe = pcf8574_probe,
|
||||||
|
.remove = pcf8574_remove,
|
||||||
|
.id_table = pcf8574_id,
|
||||||
|
|
||||||
|
.detect = pcf8574_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init pcf8574_init(void)
|
static int __init pcf8574_init(void)
|
||||||
{
|
{
|
||||||
return i2c_add_driver(&pcf8574_driver);
|
return i2c_add_driver(&pcf8574_driver);
|
||||||
|
@ -32,11 +32,8 @@
|
|||||||
#include <linux/slab.h> /* kzalloc() */
|
#include <linux/slab.h> /* kzalloc() */
|
||||||
#include <linux/sysfs.h> /* sysfs_create_group() */
|
#include <linux/sysfs.h> /* sysfs_create_group() */
|
||||||
|
|
||||||
/* Addresses to scan */
|
/* Addresses to scan: none, device can't be detected */
|
||||||
static const unsigned short normal_i2c[] = {
|
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
|
||||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
|
||||||
I2C_CLIENT_END
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Insmod parameters */
|
/* Insmod parameters */
|
||||||
I2C_CLIENT_INSMOD;
|
I2C_CLIENT_INSMOD;
|
||||||
@ -44,24 +41,9 @@ I2C_CLIENT_INSMOD;
|
|||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct pcf8575_data {
|
struct pcf8575_data {
|
||||||
struct i2c_client client;
|
|
||||||
int write; /* last written value, or error code */
|
int write; /* last written value, or error code */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pcf8575_attach_adapter(struct i2c_adapter *adapter);
|
|
||||||
static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind);
|
|
||||||
static int pcf8575_detach_client(struct i2c_client *client);
|
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
|
||||||
static struct i2c_driver pcf8575_driver = {
|
|
||||||
.driver = {
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.name = "pcf8575",
|
|
||||||
},
|
|
||||||
.attach_adapter = pcf8575_attach_adapter,
|
|
||||||
.detach_client = pcf8575_detach_client,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* following are the sysfs callback functions */
|
/* following are the sysfs callback functions */
|
||||||
static ssize_t show_read(struct device *dev, struct device_attribute *attr,
|
static ssize_t show_read(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
@ -126,75 +108,77 @@ static const struct attribute_group pcf8575_attr_group = {
|
|||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int pcf8575_attach_adapter(struct i2c_adapter *adapter)
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
|
static int pcf8575_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
return i2c_probe(adapter, &addr_data, pcf8575_detect);
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
|
||||||
static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
struct pcf8575_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
|
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* This is the place to detect whether the chip at the specified
|
||||||
|
address really is a PCF8575 chip. However, there is no method known
|
||||||
|
to detect whether an I2C chip is a PCF8575 or any other I2C chip. */
|
||||||
|
|
||||||
|
strlcpy(info->type, "pcf8575", I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pcf8575_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct pcf8575_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet. */
|
|
||||||
data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL);
|
data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
i2c_set_clientdata(client, data);
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &pcf8575_driver;
|
|
||||||
strlcpy(client->name, "pcf8575", I2C_NAME_SIZE);
|
|
||||||
data->write = -EAGAIN;
|
data->write = -EAGAIN;
|
||||||
|
|
||||||
/* This is the place to detect whether the chip at the specified
|
|
||||||
address really is a PCF8575 chip. However, there is no method known
|
|
||||||
to detect whether an I2C chip is a PCF8575 or any other I2C chip. */
|
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
err = i2c_attach_client(client);
|
|
||||||
if (err)
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group);
|
err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group);
|
||||||
if (err)
|
if (err)
|
||||||
goto exit_detach;
|
goto exit_free;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_free:
|
exit_free:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pcf8575_detach_client(struct i2c_client *client)
|
static int pcf8575_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
|
|
||||||
sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group);
|
sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group);
|
||||||
|
|
||||||
err = i2c_detach_client(client);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(i2c_get_clientdata(client));
|
kfree(i2c_get_clientdata(client));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id pcf8575_id[] = {
|
||||||
|
{ "pcf8575", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct i2c_driver pcf8575_driver = {
|
||||||
|
.driver = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.name = "pcf8575",
|
||||||
|
},
|
||||||
|
.probe = pcf8575_probe,
|
||||||
|
.remove = pcf8575_remove,
|
||||||
|
.id_table = pcf8575_id,
|
||||||
|
|
||||||
|
.detect = pcf8575_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init pcf8575_init(void)
|
static int __init pcf8575_init(void)
|
||||||
{
|
{
|
||||||
return i2c_add_driver(&pcf8575_driver);
|
return i2c_add_driver(&pcf8575_driver);
|
||||||
|
@ -72,28 +72,15 @@ MODULE_PARM_DESC(input_mode,
|
|||||||
#define REG_TO_SIGNED(reg) (((reg) & 0x80)?((reg) - 256):(reg))
|
#define REG_TO_SIGNED(reg) (((reg) & 0x80)?((reg) - 256):(reg))
|
||||||
|
|
||||||
struct pcf8591_data {
|
struct pcf8591_data {
|
||||||
struct i2c_client client;
|
|
||||||
struct mutex update_lock;
|
struct mutex update_lock;
|
||||||
|
|
||||||
u8 control;
|
u8 control;
|
||||||
u8 aout;
|
u8 aout;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pcf8591_attach_adapter(struct i2c_adapter *adapter);
|
|
||||||
static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind);
|
|
||||||
static int pcf8591_detach_client(struct i2c_client *client);
|
|
||||||
static void pcf8591_init_client(struct i2c_client *client);
|
static void pcf8591_init_client(struct i2c_client *client);
|
||||||
static int pcf8591_read_channel(struct device *dev, int channel);
|
static int pcf8591_read_channel(struct device *dev, int channel);
|
||||||
|
|
||||||
/* This is the driver that will be inserted */
|
|
||||||
static struct i2c_driver pcf8591_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "pcf8591",
|
|
||||||
},
|
|
||||||
.attach_adapter = pcf8591_attach_adapter,
|
|
||||||
.detach_client = pcf8591_detach_client,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* following are the sysfs callback functions */
|
/* following are the sysfs callback functions */
|
||||||
#define show_in_channel(channel) \
|
#define show_in_channel(channel) \
|
||||||
static ssize_t show_in##channel##_input(struct device *dev, struct device_attribute *attr, char *buf) \
|
static ssize_t show_in##channel##_input(struct device *dev, struct device_attribute *attr, char *buf) \
|
||||||
@ -180,58 +167,46 @@ static const struct attribute_group pcf8591_attr_group_opt = {
|
|||||||
/*
|
/*
|
||||||
* Real code
|
* Real code
|
||||||
*/
|
*/
|
||||||
static int pcf8591_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
|
||||||
return i2c_probe(adapter, &addr_data, pcf8591_detect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is called by i2c_probe */
|
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||||
static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
|
static int pcf8591_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info)
|
||||||
{
|
{
|
||||||
struct i2c_client *client;
|
struct i2c_adapter *adapter = client->adapter;
|
||||||
struct pcf8591_data *data;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE
|
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE
|
||||||
| I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
| I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* Now, we would do the remaining detection. But the PCF8591 is plainly
|
||||||
|
impossible to detect! Stupid chip. */
|
||||||
|
|
||||||
|
strlcpy(info->type, "pcf8591", I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pcf8591_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct pcf8591_data *data;
|
||||||
|
int err;
|
||||||
|
|
||||||
/* OK. For now, we presume we have a valid client. We now create the
|
|
||||||
client structure, even though we cannot fill it completely yet. */
|
|
||||||
if (!(data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) {
|
if (!(data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
client = &data->client;
|
|
||||||
i2c_set_clientdata(client, data);
|
i2c_set_clientdata(client, data);
|
||||||
client->addr = address;
|
|
||||||
client->adapter = adapter;
|
|
||||||
client->driver = &pcf8591_driver;
|
|
||||||
|
|
||||||
/* Now, we would do the remaining detection. But the PCF8591 is plainly
|
|
||||||
impossible to detect! Stupid chip. */
|
|
||||||
|
|
||||||
/* Determine the chip type - only one kind supported! */
|
|
||||||
if (kind <= 0)
|
|
||||||
kind = pcf8591;
|
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put it into the global
|
|
||||||
list */
|
|
||||||
strlcpy(client->name, "pcf8591", I2C_NAME_SIZE);
|
|
||||||
mutex_init(&data->update_lock);
|
mutex_init(&data->update_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(client)))
|
|
||||||
goto exit_kfree;
|
|
||||||
|
|
||||||
/* Initialize the PCF8591 chip */
|
/* Initialize the PCF8591 chip */
|
||||||
pcf8591_init_client(client);
|
pcf8591_init_client(client);
|
||||||
|
|
||||||
/* Register sysfs hooks */
|
/* Register sysfs hooks */
|
||||||
err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group);
|
err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group);
|
||||||
if (err)
|
if (err)
|
||||||
goto exit_detach;
|
goto exit_kfree;
|
||||||
|
|
||||||
/* Register input2 if not in "two differential inputs" mode */
|
/* Register input2 if not in "two differential inputs" mode */
|
||||||
if (input_mode != 3) {
|
if (input_mode != 3) {
|
||||||
@ -252,24 +227,16 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
exit_sysfs_remove:
|
exit_sysfs_remove:
|
||||||
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
|
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
|
||||||
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
|
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
|
||||||
exit_detach:
|
|
||||||
i2c_detach_client(client);
|
|
||||||
exit_kfree:
|
exit_kfree:
|
||||||
kfree(data);
|
kfree(data);
|
||||||
exit:
|
exit:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pcf8591_detach_client(struct i2c_client *client)
|
static int pcf8591_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
|
|
||||||
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
|
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
|
||||||
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
|
sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
|
||||||
|
|
||||||
if ((err = i2c_detach_client(client)))
|
|
||||||
return err;
|
|
||||||
|
|
||||||
kfree(i2c_get_clientdata(client));
|
kfree(i2c_get_clientdata(client));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -316,6 +283,25 @@ static int pcf8591_read_channel(struct device *dev, int channel)
|
|||||||
return (10 * value);
|
return (10 * value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id pcf8591_id[] = {
|
||||||
|
{ "pcf8591", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, pcf8591_id);
|
||||||
|
|
||||||
|
static struct i2c_driver pcf8591_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "pcf8591",
|
||||||
|
},
|
||||||
|
.probe = pcf8591_probe,
|
||||||
|
.remove = pcf8591_remove,
|
||||||
|
.id_table = pcf8591_id,
|
||||||
|
|
||||||
|
.class = I2C_CLASS_HWMON, /* Nearest choice */
|
||||||
|
.detect = pcf8591_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init pcf8591_init(void)
|
static int __init pcf8591_init(void)
|
||||||
{
|
{
|
||||||
if (input_mode < 0 || input_mode > 3) {
|
if (input_mode < 0 || input_mode > 3) {
|
||||||
|
@ -654,6 +654,10 @@ int i2c_del_adapter(struct i2c_adapter *adap)
|
|||||||
|
|
||||||
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
|
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
|
||||||
|
|
||||||
|
/* Clear the device structure in case this adapter is ever going to be
|
||||||
|
added again */
|
||||||
|
memset(&adap->dev, 0, sizeof(adap->dev));
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&core_lock);
|
mutex_unlock(&core_lock);
|
||||||
return res;
|
return res;
|
||||||
|
@ -94,21 +94,31 @@ static const u8 ds2482_chan_rd[8] =
|
|||||||
#define DS2482_REG_STS_1WB 0x01
|
#define DS2482_REG_STS_1WB 0x01
|
||||||
|
|
||||||
|
|
||||||
static int ds2482_attach_adapter(struct i2c_adapter *adapter);
|
static int ds2482_probe(struct i2c_client *client,
|
||||||
static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind);
|
const struct i2c_device_id *id);
|
||||||
static int ds2482_detach_client(struct i2c_client *client);
|
static int ds2482_detect(struct i2c_client *client, int kind,
|
||||||
|
struct i2c_board_info *info);
|
||||||
|
static int ds2482_remove(struct i2c_client *client);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Driver data (common to all clients)
|
* Driver data (common to all clients)
|
||||||
*/
|
*/
|
||||||
|
static const struct i2c_device_id ds2482_id[] = {
|
||||||
|
{ "ds2482", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
static struct i2c_driver ds2482_driver = {
|
static struct i2c_driver ds2482_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "ds2482",
|
.name = "ds2482",
|
||||||
},
|
},
|
||||||
.attach_adapter = ds2482_attach_adapter,
|
.probe = ds2482_probe,
|
||||||
.detach_client = ds2482_detach_client,
|
.remove = ds2482_remove,
|
||||||
|
.id_table = ds2482_id,
|
||||||
|
.detect = ds2482_detect,
|
||||||
|
.address_data = &addr_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -124,7 +134,7 @@ struct ds2482_w1_chan {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ds2482_data {
|
struct ds2482_data {
|
||||||
struct i2c_client client;
|
struct i2c_client *client;
|
||||||
struct mutex access_lock;
|
struct mutex access_lock;
|
||||||
|
|
||||||
/* 1-wire interface(s) */
|
/* 1-wire interface(s) */
|
||||||
@ -147,7 +157,7 @@ struct ds2482_data {
|
|||||||
static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
|
static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
|
||||||
{
|
{
|
||||||
if (pdev->read_prt != read_ptr) {
|
if (pdev->read_prt != read_ptr) {
|
||||||
if (i2c_smbus_write_byte_data(&pdev->client,
|
if (i2c_smbus_write_byte_data(pdev->client,
|
||||||
DS2482_CMD_SET_READ_PTR,
|
DS2482_CMD_SET_READ_PTR,
|
||||||
read_ptr) < 0)
|
read_ptr) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -167,7 +177,7 @@ static inline int ds2482_select_register(struct ds2482_data *pdev, u8 read_ptr)
|
|||||||
*/
|
*/
|
||||||
static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
|
static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
|
||||||
{
|
{
|
||||||
if (i2c_smbus_write_byte(&pdev->client, cmd) < 0)
|
if (i2c_smbus_write_byte(pdev->client, cmd) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pdev->read_prt = DS2482_PTR_CODE_STATUS;
|
pdev->read_prt = DS2482_PTR_CODE_STATUS;
|
||||||
@ -187,7 +197,7 @@ static inline int ds2482_send_cmd(struct ds2482_data *pdev, u8 cmd)
|
|||||||
static inline int ds2482_send_cmd_data(struct ds2482_data *pdev,
|
static inline int ds2482_send_cmd_data(struct ds2482_data *pdev,
|
||||||
u8 cmd, u8 byte)
|
u8 cmd, u8 byte)
|
||||||
{
|
{
|
||||||
if (i2c_smbus_write_byte_data(&pdev->client, cmd, byte) < 0)
|
if (i2c_smbus_write_byte_data(pdev->client, cmd, byte) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* all cmds leave in STATUS, except CONFIG */
|
/* all cmds leave in STATUS, except CONFIG */
|
||||||
@ -216,7 +226,7 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
|
|||||||
|
|
||||||
if (!ds2482_select_register(pdev, DS2482_PTR_CODE_STATUS)) {
|
if (!ds2482_select_register(pdev, DS2482_PTR_CODE_STATUS)) {
|
||||||
do {
|
do {
|
||||||
temp = i2c_smbus_read_byte(&pdev->client);
|
temp = i2c_smbus_read_byte(pdev->client);
|
||||||
} while ((temp >= 0) && (temp & DS2482_REG_STS_1WB) &&
|
} while ((temp >= 0) && (temp & DS2482_REG_STS_1WB) &&
|
||||||
(++retries < DS2482_WAIT_IDLE_TIMEOUT));
|
(++retries < DS2482_WAIT_IDLE_TIMEOUT));
|
||||||
}
|
}
|
||||||
@ -238,13 +248,13 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
|
|||||||
*/
|
*/
|
||||||
static int ds2482_set_channel(struct ds2482_data *pdev, u8 channel)
|
static int ds2482_set_channel(struct ds2482_data *pdev, u8 channel)
|
||||||
{
|
{
|
||||||
if (i2c_smbus_write_byte_data(&pdev->client, DS2482_CMD_CHANNEL_SELECT,
|
if (i2c_smbus_write_byte_data(pdev->client, DS2482_CMD_CHANNEL_SELECT,
|
||||||
ds2482_chan_wr[channel]) < 0)
|
ds2482_chan_wr[channel]) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pdev->read_prt = DS2482_PTR_CODE_CHANNEL;
|
pdev->read_prt = DS2482_PTR_CODE_CHANNEL;
|
||||||
pdev->channel = -1;
|
pdev->channel = -1;
|
||||||
if (i2c_smbus_read_byte(&pdev->client) == ds2482_chan_rd[channel]) {
|
if (i2c_smbus_read_byte(pdev->client) == ds2482_chan_rd[channel]) {
|
||||||
pdev->channel = channel;
|
pdev->channel = channel;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -368,7 +378,7 @@ static u8 ds2482_w1_read_byte(void *data)
|
|||||||
ds2482_select_register(pdev, DS2482_PTR_CODE_DATA);
|
ds2482_select_register(pdev, DS2482_PTR_CODE_DATA);
|
||||||
|
|
||||||
/* Read the data byte */
|
/* Read the data byte */
|
||||||
result = i2c_smbus_read_byte(&pdev->client);
|
result = i2c_smbus_read_byte(pdev->client);
|
||||||
|
|
||||||
mutex_unlock(&pdev->access_lock);
|
mutex_unlock(&pdev->access_lock);
|
||||||
|
|
||||||
@ -415,47 +425,38 @@ static u8 ds2482_w1_reset_bus(void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
static int ds2482_detect(struct i2c_client *client, int kind,
|
||||||
* Called to see if the device exists on an i2c bus.
|
struct i2c_board_info *info)
|
||||||
*/
|
|
||||||
static int ds2482_attach_adapter(struct i2c_adapter *adapter)
|
|
||||||
{
|
{
|
||||||
return i2c_probe(adapter, &addr_data, ds2482_detect);
|
if (!i2c_check_functionality(client->adapter,
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following function does more than just detection. If detection
|
|
||||||
* succeeds, it also registers the new chip.
|
|
||||||
*/
|
|
||||||
static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
|
|
||||||
{
|
|
||||||
struct ds2482_data *data;
|
|
||||||
struct i2c_client *new_client;
|
|
||||||
int err = 0;
|
|
||||||
int temp1;
|
|
||||||
int idx;
|
|
||||||
|
|
||||||
if (!i2c_check_functionality(adapter,
|
|
||||||
I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
|
I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
|
||||||
I2C_FUNC_SMBUS_BYTE))
|
I2C_FUNC_SMBUS_BYTE))
|
||||||
goto exit;
|
return -ENODEV;
|
||||||
|
|
||||||
|
strlcpy(info->type, "ds2482", I2C_NAME_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ds2482_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct ds2482_data *data;
|
||||||
|
int err = -ENODEV;
|
||||||
|
int temp1;
|
||||||
|
int idx;
|
||||||
|
|
||||||
if (!(data = kzalloc(sizeof(struct ds2482_data), GFP_KERNEL))) {
|
if (!(data = kzalloc(sizeof(struct ds2482_data), GFP_KERNEL))) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_client = &data->client;
|
data->client = client;
|
||||||
i2c_set_clientdata(new_client, data);
|
i2c_set_clientdata(client, data);
|
||||||
new_client->addr = address;
|
|
||||||
new_client->driver = &ds2482_driver;
|
|
||||||
new_client->adapter = adapter;
|
|
||||||
|
|
||||||
/* Reset the device (sets the read_ptr to status) */
|
/* Reset the device (sets the read_ptr to status) */
|
||||||
if (ds2482_send_cmd(data, DS2482_CMD_RESET) < 0) {
|
if (ds2482_send_cmd(data, DS2482_CMD_RESET) < 0) {
|
||||||
dev_dbg(&adapter->dev, "DS2482 reset failed at 0x%02x.\n",
|
dev_warn(&client->dev, "DS2482 reset failed.\n");
|
||||||
address);
|
|
||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,10 +464,10 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
ndelay(525);
|
ndelay(525);
|
||||||
|
|
||||||
/* Read the status byte - only reset bit and line should be set */
|
/* Read the status byte - only reset bit and line should be set */
|
||||||
temp1 = i2c_smbus_read_byte(new_client);
|
temp1 = i2c_smbus_read_byte(client);
|
||||||
if (temp1 != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) {
|
if (temp1 != (DS2482_REG_STS_LL | DS2482_REG_STS_RST)) {
|
||||||
dev_dbg(&adapter->dev, "DS2482 (0x%02x) reset status "
|
dev_warn(&client->dev, "DS2482 reset status "
|
||||||
"0x%02X - not a DS2482\n", address, temp1);
|
"0x%02X - not a DS2482\n", temp1);
|
||||||
goto exit_free;
|
goto exit_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,16 +479,8 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
/* Set all config items to 0 (off) */
|
/* Set all config items to 0 (off) */
|
||||||
ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG, 0xF0);
|
ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG, 0xF0);
|
||||||
|
|
||||||
/* We can fill in the remaining client fields */
|
|
||||||
snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00",
|
|
||||||
data->w1_count);
|
|
||||||
|
|
||||||
mutex_init(&data->access_lock);
|
mutex_init(&data->access_lock);
|
||||||
|
|
||||||
/* Tell the I2C layer a new client has arrived */
|
|
||||||
if ((err = i2c_attach_client(new_client)))
|
|
||||||
goto exit_free;
|
|
||||||
|
|
||||||
/* Register 1-wire interface(s) */
|
/* Register 1-wire interface(s) */
|
||||||
for (idx = 0; idx < data->w1_count; idx++) {
|
for (idx = 0; idx < data->w1_count; idx++) {
|
||||||
data->w1_ch[idx].pdev = data;
|
data->w1_ch[idx].pdev = data;
|
||||||
@ -511,8 +504,6 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exit_w1_remove:
|
exit_w1_remove:
|
||||||
i2c_detach_client(new_client);
|
|
||||||
|
|
||||||
for (idx = 0; idx < data->w1_count; idx++) {
|
for (idx = 0; idx < data->w1_count; idx++) {
|
||||||
if (data->w1_ch[idx].pdev != NULL)
|
if (data->w1_ch[idx].pdev != NULL)
|
||||||
w1_remove_master_device(&data->w1_ch[idx].w1_bm);
|
w1_remove_master_device(&data->w1_ch[idx].w1_bm);
|
||||||
@ -523,10 +514,10 @@ exit:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ds2482_detach_client(struct i2c_client *client)
|
static int ds2482_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct ds2482_data *data = i2c_get_clientdata(client);
|
struct ds2482_data *data = i2c_get_clientdata(client);
|
||||||
int err, idx;
|
int idx;
|
||||||
|
|
||||||
/* Unregister the 1-wire bridge(s) */
|
/* Unregister the 1-wire bridge(s) */
|
||||||
for (idx = 0; idx < data->w1_count; idx++) {
|
for (idx = 0; idx < data->w1_count; idx++) {
|
||||||
@ -534,13 +525,6 @@ static int ds2482_detach_client(struct i2c_client *client)
|
|||||||
w1_remove_master_device(&data->w1_ch[idx].w1_bm);
|
w1_remove_master_device(&data->w1_ch[idx].w1_bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detach the i2c device */
|
|
||||||
if ((err = i2c_detach_client(client))) {
|
|
||||||
dev_err(&client->dev,
|
|
||||||
"Deregistration failed, client not detached.\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free the memory */
|
/* Free the memory */
|
||||||
kfree(data);
|
kfree(data);
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user