5a0e3ad6af
percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
267 lines
7.0 KiB
C
267 lines
7.0 KiB
C
/*
|
|
* Dallas Semiconductor DS1682 Elapsed Time Recorder device driver
|
|
*
|
|
* Written by: Grant Likely <grant.likely@secretlab.ca>
|
|
*
|
|
* Copyright (C) 2007 Secret Lab Technologies Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
/*
|
|
* The DS1682 elapsed timer recorder is a simple device that implements
|
|
* one elapsed time counter, one event counter, an alarm signal and 10
|
|
* bytes of general purpose EEPROM.
|
|
*
|
|
* This driver provides access to the DS1682 counters and user data via
|
|
* the sysfs. The following attributes are added to the device node:
|
|
* elapsed_time (u32): Total elapsed event time in ms resolution
|
|
* alarm_time (u32): When elapsed time exceeds the value in alarm_time,
|
|
* then the alarm pin is asserted.
|
|
* event_count (u16): number of times the event pin has gone low.
|
|
* eeprom (u8[10]): general purpose EEPROM
|
|
*
|
|
* Counter registers and user data are both read/write unless the device
|
|
* has been write protected. This driver does not support turning off write
|
|
* protection. Once write protection is turned on, it is impossible to
|
|
* turn it off again, so I have left the feature out of this driver to avoid
|
|
* accidental enabling, but it is trivial to add write protect support.
|
|
*
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/string.h>
|
|
#include <linux/list.h>
|
|
#include <linux/sysfs.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/hwmon-sysfs.h>
|
|
|
|
/* Device registers */
|
|
#define DS1682_REG_CONFIG 0x00
|
|
#define DS1682_REG_ALARM 0x01
|
|
#define DS1682_REG_ELAPSED 0x05
|
|
#define DS1682_REG_EVT_CNTR 0x09
|
|
#define DS1682_REG_EEPROM 0x0b
|
|
#define DS1682_REG_RESET 0x1d
|
|
#define DS1682_REG_WRITE_DISABLE 0x1e
|
|
#define DS1682_REG_WRITE_MEM_DISABLE 0x1f
|
|
|
|
#define DS1682_EEPROM_SIZE 10
|
|
|
|
/*
|
|
* Generic counter attributes
|
|
*/
|
|
static ssize_t ds1682_show(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
__le32 val = 0;
|
|
int rc;
|
|
|
|
dev_dbg(dev, "ds1682_show() called on %s\n", attr->attr.name);
|
|
|
|
/* Read the register */
|
|
rc = i2c_smbus_read_i2c_block_data(client, sattr->index, sattr->nr,
|
|
(u8 *) & val);
|
|
if (rc < 0)
|
|
return -EIO;
|
|
|
|
/* Special case: the 32 bit regs are time values with 1/4s
|
|
* resolution, scale them up to milliseconds */
|
|
if (sattr->nr == 4)
|
|
return sprintf(buf, "%llu\n",
|
|
((unsigned long long)le32_to_cpu(val)) * 250);
|
|
|
|
/* Format the output string and return # of bytes */
|
|
return sprintf(buf, "%li\n", (long)le32_to_cpu(val));
|
|
}
|
|
|
|
static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr,
|
|
const char *buf, size_t count)
|
|
{
|
|
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
|
|
struct i2c_client *client = to_i2c_client(dev);
|
|
char *endp;
|
|
u64 val;
|
|
__le32 val_le;
|
|
int rc;
|
|
|
|
dev_dbg(dev, "ds1682_store() called on %s\n", attr->attr.name);
|
|
|
|
/* Decode input */
|
|
val = simple_strtoull(buf, &endp, 0);
|
|
if (buf == endp) {
|
|
dev_dbg(dev, "input string not a number\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Special case: the 32 bit regs are time values with 1/4s
|
|
* resolution, scale input down to quarter-seconds */
|
|
if (sattr->nr == 4)
|
|
do_div(val, 250);
|
|
|
|
/* write out the value */
|
|
val_le = cpu_to_le32(val);
|
|
rc = i2c_smbus_write_i2c_block_data(client, sattr->index, sattr->nr,
|
|
(u8 *) & val_le);
|
|
if (rc < 0) {
|
|
dev_err(dev, "register write failed; reg=0x%x, size=%i\n",
|
|
sattr->index, sattr->nr);
|
|
return -EIO;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/*
|
|
* Simple register attributes
|
|
*/
|
|
static SENSOR_DEVICE_ATTR_2(elapsed_time, S_IRUGO | S_IWUSR, ds1682_show,
|
|
ds1682_store, 4, DS1682_REG_ELAPSED);
|
|
static SENSOR_DEVICE_ATTR_2(alarm_time, S_IRUGO | S_IWUSR, ds1682_show,
|
|
ds1682_store, 4, DS1682_REG_ALARM);
|
|
static SENSOR_DEVICE_ATTR_2(event_count, S_IRUGO | S_IWUSR, ds1682_show,
|
|
ds1682_store, 2, DS1682_REG_EVT_CNTR);
|
|
|
|
static const struct attribute_group ds1682_group = {
|
|
.attrs = (struct attribute *[]) {
|
|
&sensor_dev_attr_elapsed_time.dev_attr.attr,
|
|
&sensor_dev_attr_alarm_time.dev_attr.attr,
|
|
&sensor_dev_attr_event_count.dev_attr.attr,
|
|
NULL,
|
|
},
|
|
};
|
|
|
|
/*
|
|
* User data attribute
|
|
*/
|
|
static ssize_t ds1682_eeprom_read(struct kobject *kobj, struct bin_attribute *attr,
|
|
char *buf, loff_t off, size_t count)
|
|
{
|
|
struct i2c_client *client = kobj_to_i2c_client(kobj);
|
|
int rc;
|
|
|
|
dev_dbg(&client->dev, "ds1682_eeprom_read(p=%p, off=%lli, c=%zi)\n",
|
|
buf, off, count);
|
|
|
|
if (off >= DS1682_EEPROM_SIZE)
|
|
return 0;
|
|
|
|
if (off + count > DS1682_EEPROM_SIZE)
|
|
count = DS1682_EEPROM_SIZE - off;
|
|
|
|
rc = i2c_smbus_read_i2c_block_data(client, DS1682_REG_EEPROM + off,
|
|
count, buf);
|
|
if (rc < 0)
|
|
return -EIO;
|
|
|
|
return count;
|
|
}
|
|
|
|
static ssize_t ds1682_eeprom_write(struct kobject *kobj, struct bin_attribute *attr,
|
|
char *buf, loff_t off, size_t count)
|
|
{
|
|
struct i2c_client *client = kobj_to_i2c_client(kobj);
|
|
|
|
dev_dbg(&client->dev, "ds1682_eeprom_write(p=%p, off=%lli, c=%zi)\n",
|
|
buf, off, count);
|
|
|
|
if (off >= DS1682_EEPROM_SIZE)
|
|
return -ENOSPC;
|
|
|
|
if (off + count > DS1682_EEPROM_SIZE)
|
|
count = DS1682_EEPROM_SIZE - off;
|
|
|
|
/* Write out to the device */
|
|
if (i2c_smbus_write_i2c_block_data(client, DS1682_REG_EEPROM + off,
|
|
count, buf) < 0)
|
|
return -EIO;
|
|
|
|
return count;
|
|
}
|
|
|
|
static struct bin_attribute ds1682_eeprom_attr = {
|
|
.attr = {
|
|
.name = "eeprom",
|
|
.mode = S_IRUGO | S_IWUSR,
|
|
},
|
|
.size = DS1682_EEPROM_SIZE,
|
|
.read = ds1682_eeprom_read,
|
|
.write = ds1682_eeprom_write,
|
|
};
|
|
|
|
/*
|
|
* Called when a ds1682 device is matched with this driver
|
|
*/
|
|
static int ds1682_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
int rc;
|
|
|
|
if (!i2c_check_functionality(client->adapter,
|
|
I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
|
dev_err(&client->dev, "i2c bus does not support the ds1682\n");
|
|
rc = -ENODEV;
|
|
goto exit;
|
|
}
|
|
|
|
rc = sysfs_create_group(&client->dev.kobj, &ds1682_group);
|
|
if (rc)
|
|
goto exit;
|
|
|
|
rc = sysfs_create_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
|
|
if (rc)
|
|
goto exit_bin_attr;
|
|
|
|
return 0;
|
|
|
|
exit_bin_attr:
|
|
sysfs_remove_group(&client->dev.kobj, &ds1682_group);
|
|
exit:
|
|
return rc;
|
|
}
|
|
|
|
static int ds1682_remove(struct i2c_client *client)
|
|
{
|
|
sysfs_remove_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
|
|
sysfs_remove_group(&client->dev.kobj, &ds1682_group);
|
|
return 0;
|
|
}
|
|
|
|
static const struct i2c_device_id ds1682_id[] = {
|
|
{ "ds1682", 0 },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(i2c, ds1682_id);
|
|
|
|
static struct i2c_driver ds1682_driver = {
|
|
.driver = {
|
|
.name = "ds1682",
|
|
},
|
|
.probe = ds1682_probe,
|
|
.remove = ds1682_remove,
|
|
.id_table = ds1682_id,
|
|
};
|
|
|
|
static int __init ds1682_init(void)
|
|
{
|
|
return i2c_add_driver(&ds1682_driver);
|
|
}
|
|
|
|
static void __exit ds1682_exit(void)
|
|
{
|
|
i2c_del_driver(&ds1682_driver);
|
|
}
|
|
|
|
MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
|
|
MODULE_DESCRIPTION("DS1682 Elapsed Time Indicator driver");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
module_init(ds1682_init);
|
|
module_exit(ds1682_exit);
|