diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-02-11 17:00:36 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2010-02-11 17:00:36 +1100 |
commit | a1a0b9e639d9b467ea178f8e11be75fd29a00d3d (patch) | |
tree | ff8431fa367a8d047263ce0d0902836ef9f419d5 | |
parent | 4e3eb9732253cb64cc1983d9cb108a1aaceea7fc (diff) | |
parent | e41aa77b6280ed6e7b7c95f83f4bab355c64d8ab (diff) |
Merge remote branch 'als/for-next'
-rw-r--r-- | Documentation/ABI/testing/sysfs-class-als | 18 | ||||
-rw-r--r-- | MAINTAINERS | 8 | ||||
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/als/Kconfig | 24 | ||||
-rw-r--r-- | drivers/als/Makefile | 7 | ||||
-rw-r--r-- | drivers/als/als_sys.c | 116 | ||||
-rw-r--r-- | drivers/als/tsl2550.c (renamed from drivers/i2c/chips/tsl2550.c) | 96 | ||||
-rw-r--r-- | drivers/i2c/Kconfig | 1 | ||||
-rw-r--r-- | drivers/i2c/Makefile | 2 | ||||
-rw-r--r-- | drivers/i2c/chips/Kconfig | 19 | ||||
-rw-r--r-- | drivers/i2c/chips/Makefile | 18 | ||||
-rw-r--r-- | include/linux/als_sys.h | 35 |
13 files changed, 271 insertions, 76 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-als b/Documentation/ABI/testing/sysfs-class-als new file mode 100644 index 000000000000..732f449ef22f --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-als @@ -0,0 +1,18 @@ +What: /sys/class/als/.../illuminance +Date: Sep. 2009 +KernelVersion: 2.6.32 +Contact: Zhang Rui <rui.zhang@intel.com> +Description: Current Ambient Light Illuminance reported by + native ALS driver + Unit: lux (lumens per square meter) + RO + +What: /sys/class/als/.../exposure_time[n] +Date: Dec. 2009 +KernelVersion: 2.6.32 +Contact: Jonathan Cameron <jic23@cam.ac.uk> +Description: Sensor exposure time. In some devices this + corresponds to the combined time needed to + to internally read several different sensors. + Unit: microseconds + RW diff --git a/MAINTAINERS b/MAINTAINERS index adc0154fc315..8878cbbe5351 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -415,6 +415,14 @@ M: Matt Turner <mattst88@gmail.com> L: linux-alpha@vger.kernel.org F: arch/alpha/ +AMBIENT LIGHT SENSOR +M: Zhang Rui <rui.zhang@intel.com> +M: Jonathan Cameron <jic23@cam.ac.uk> +S: Supported +F: include/linux/als_sys.h +F: drivers/als/ +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/als.git + AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER M: Thomas Dahlmann <dahlmann.thomas@arcor.de> L: linux-geode@lists.infradead.org (moderated for non-subscribers) diff --git a/drivers/Kconfig b/drivers/Kconfig index 368ae6d3a096..0aaf587b8cd8 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -60,6 +60,8 @@ source "drivers/power/Kconfig" source "drivers/hwmon/Kconfig" +source "drivers/als/Kconfig" + source "drivers/thermal/Kconfig" source "drivers/watchdog/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 19e82b9c91c2..084a7f620cd6 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_PPS) += pps/ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_POWER_SUPPLY) += power/ obj-$(CONFIG_HWMON) += hwmon/ +obj-$(CONFIG_ALS) += als/ obj-$(CONFIG_THERMAL) += thermal/ obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_PHONE) += telephony/ diff --git a/drivers/als/Kconfig b/drivers/als/Kconfig new file mode 100644 index 000000000000..1564ffca5e75 --- /dev/null +++ b/drivers/als/Kconfig @@ -0,0 +1,24 @@ +# +# Ambient Light Sensor sysfs device configuration +# + +menuconfig ALS + tristate "Ambient Light Sensor sysfs device" + help + This framework provides a generic sysfs I/F for Ambient Light + Sensor devices. + If you want this support, you should say Y or M here. + +if ALS + +config ALS_TSL2550 + tristate "Taos TSL2550 ambient light sensor" + depends on EXPERIMENTAL && I2C + help + If you say yes here you get support for the Taos TSL2550 + ambient light sensor. + + This driver can also be built as a module. If so, the module + will be called tsl2550. + +endif #ALS diff --git a/drivers/als/Makefile b/drivers/als/Makefile new file mode 100644 index 000000000000..314c645b79eb --- /dev/null +++ b/drivers/als/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for sensor chip drivers. +# + +obj-$(CONFIG_ALS) += als_sys.o + +obj-$(CONFIG_ALS_TSL2550) += tsl2550.o diff --git a/drivers/als/als_sys.c b/drivers/als/als_sys.c new file mode 100644 index 000000000000..aa15ad86cd85 --- /dev/null +++ b/drivers/als/als_sys.c @@ -0,0 +1,116 @@ +/* + * als_sys.c - Ambient Light Sensor Sysfs support. + * + * Copyright (C) 2009 Intel Corp + * Copyright (C) 2009 Zhang Rui <rui.zhang@intel.com> + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/kdev_t.h> +#include <linux/idr.h> + +MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>"); +MODULE_DESCRIPTION("Ambient Light Sensor sysfs/class support"); +MODULE_LICENSE("GPL"); + +#define ALS_ID_PREFIX "als" +#define ALS_ID_FORMAT ALS_ID_PREFIX "%d" + +static struct class *als_class; + +static DEFINE_IDR(als_idr); +static DEFINE_SPINLOCK(idr_lock); + +/** + * als_device_register - register a new Ambient Light Sensor class device + * @parent: the device to register. + * + * Returns the pointer to the new device + */ +struct device *als_device_register(struct device *dev) +{ + int id, err; + struct device *alsdev; + +again: + if (unlikely(idr_pre_get(&als_idr, GFP_KERNEL) == 0)) + return ERR_PTR(-ENOMEM); + + spin_lock(&idr_lock); + err = idr_get_new(&als_idr, NULL, &id); + spin_unlock(&idr_lock); + + if (unlikely(err == -EAGAIN)) + goto again; + else if (unlikely(err)) + return ERR_PTR(err); + + id = id & MAX_ID_MASK; + alsdev = device_create(als_class, dev, MKDEV(0, 0), NULL, + ALS_ID_FORMAT, id); + + if (IS_ERR(alsdev)) { + spin_lock(&idr_lock); + idr_remove(&als_idr, id); + spin_unlock(&idr_lock); + } + + return alsdev; +} +EXPORT_SYMBOL(als_device_register); + +/** + * als_device_unregister - removes the registered ALS class device + * @dev: the class device to destroy. + */ +void als_device_unregister(struct device *dev) +{ + int id; + + if (likely(sscanf(dev_name(dev), ALS_ID_FORMAT, &id) == 1)) { + device_unregister(dev); + spin_lock(&idr_lock); + idr_remove(&als_idr, id); + spin_unlock(&idr_lock); + } else + dev_dbg(dev->parent, + "als_device_unregister() failed: bad class ID!\n"); +} +EXPORT_SYMBOL(als_device_unregister); + +static int __init als_init(void) +{ + als_class = class_create(THIS_MODULE, "als"); + if (IS_ERR(als_class)) { + printk(KERN_ERR "als_sys.c: couldn't create sysfs class\n"); + return PTR_ERR(als_class); + } + return 0; +} + +static void __exit als_exit(void) +{ + class_destroy(als_class); +} + +subsys_initcall(als_init); +module_exit(als_exit); diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/als/tsl2550.c index a0702f36a72f..27745a579dc3 100644 --- a/drivers/i2c/chips/tsl2550.c +++ b/drivers/als/tsl2550.c @@ -3,6 +3,7 @@ * * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it> * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it> + * Copyright (C) 2009 Jonathan Cameron <jic23@cam.ac.uk> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,9 +25,11 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/mutex.h> +#include <linux/err.h> +#include <linux/als_sys.h> #define TSL2550_DRV_NAME "tsl2550" -#define DRIVER_VERSION "1.2" +#define DRIVER_VERSION "2.0" /* * Defines @@ -44,6 +47,7 @@ */ struct tsl2550_data { + struct device *classdev; struct i2c_client *client; struct mutex update_lock; @@ -102,15 +106,16 @@ static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd) return ret; if (!(ret & 0x80)) return -EAGAIN; + if (ret == 0x7f) + return -ERANGE; return ret & 0x7f; /* remove the "valid" bit */ } /* - * LUX calculation + * LUX calculation - note the range is dependent on combination + * of infrared level and visible light levels. */ -#define TSL2550_MAX_LUX 1846 - static const u8 ratio_lut[] = { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 99, 99, @@ -180,8 +185,7 @@ static int tsl2550_calculate_lux(u8 ch0, u8 ch1) else return -EAGAIN; - /* LUX range check */ - return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux; + return lux; } /* @@ -191,7 +195,8 @@ static int tsl2550_calculate_lux(u8 ch0, u8 ch1) static ssize_t tsl2550_show_power_state(struct device *dev, struct device_attribute *attr, char *buf) { - struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev)); + struct i2c_client *client = to_i2c_client(dev->parent); + struct tsl2550_data *data = i2c_get_clientdata(client); return sprintf(buf, "%u\n", data->power_state); } @@ -199,12 +204,13 @@ static ssize_t tsl2550_show_power_state(struct device *dev, static ssize_t tsl2550_store_power_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = to_i2c_client(dev->parent); struct tsl2550_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); + unsigned long val; int ret; - if (val < 0 || val > 1) + ret = strict_strtoul(buf, 10, &val); + if (ret || val < 0 || val > 1) return -EINVAL; mutex_lock(&data->update_lock); @@ -220,40 +226,45 @@ static ssize_t tsl2550_store_power_state(struct device *dev, static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO, tsl2550_show_power_state, tsl2550_store_power_state); -static ssize_t tsl2550_show_operating_mode(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t tsl2550_show_exposure(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev)); - - return sprintf(buf, "%u\n", data->operating_mode); + struct i2c_client *client = to_i2c_client(dev->parent); + struct tsl2550_data *data = i2c_get_clientdata(client); + if (data->operating_mode) + return sprintf(buf, "160000\n"); + else + return sprintf(buf, "800000\n"); } -static ssize_t tsl2550_store_operating_mode(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static ssize_t tsl2550_store_exposure(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) { - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = to_i2c_client(dev->parent); struct tsl2550_data *data = i2c_get_clientdata(client); - unsigned long val = simple_strtoul(buf, NULL, 10); - int ret; + unsigned long val; - if (val < 0 || val > 1) - return -EINVAL; - - if (data->power_state == 0) - return -EBUSY; + int ret = strict_strtoul(buf, 10, &val); + if (ret) + return -EINVAL; mutex_lock(&data->update_lock); - ret = tsl2550_set_operating_mode(client, val); + if (val >= 800000) + ret = tsl2550_set_operating_mode(client, 0); + else + ret = tsl2550_set_operating_mode(client, 1); mutex_unlock(&data->update_lock); - if (ret < 0) return ret; return count; } -static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO, - tsl2550_show_operating_mode, tsl2550_store_operating_mode); +static DEVICE_ATTR(exposure_time0, S_IWUSR | S_IRUGO, + tsl2550_show_exposure, tsl2550_store_exposure); static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf) { @@ -284,7 +295,7 @@ static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf) static ssize_t tsl2550_show_lux1_input(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = to_i2c_client(dev->parent); struct tsl2550_data *data = i2c_get_clientdata(client); int ret; @@ -299,13 +310,13 @@ static ssize_t tsl2550_show_lux1_input(struct device *dev, return ret; } -static DEVICE_ATTR(lux1_input, S_IRUGO, +static DEVICE_ATTR(illuminance0, S_IRUGO, tsl2550_show_lux1_input, NULL); static struct attribute *tsl2550_attributes[] = { &dev_attr_power_state.attr, - &dev_attr_operating_mode.attr, - &dev_attr_lux1_input.attr, + &dev_attr_exposure_time0.attr, + &dev_attr_illuminance0.attr, NULL }; @@ -391,14 +402,22 @@ static int __devinit tsl2550_probe(struct i2c_client *client, goto exit_kfree; /* Register sysfs hooks */ - err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group); - if (err) + data->classdev = als_device_register(&client->dev); + if (IS_ERR(data->classdev)) { + err = PTR_ERR(data->classdev); goto exit_kfree; + } + + err = sysfs_create_group(&data->classdev->kobj, &tsl2550_attr_group); + if (err) + goto exit_unreg; dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION); return 0; +exit_unreg: + als_device_unregister(data->classdev); exit_kfree: kfree(data); exit: @@ -407,12 +426,15 @@ exit: static int __devexit tsl2550_remove(struct i2c_client *client) { - sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group); + struct tsl2550_data *data = i2c_get_clientdata(client); + + sysfs_remove_group(&data->classdev->kobj, &tsl2550_attr_group); + als_device_unregister(data->classdev); /* Power down the device */ tsl2550_set_power_state(client, 0); - kfree(i2c_get_clientdata(client)); + kfree(data); return 0; } diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 8d8a00e5a30e..5c33a71de13e 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -63,7 +63,6 @@ config I2C_HELPER_AUTO source drivers/i2c/algos/Kconfig source drivers/i2c/busses/Kconfig -source drivers/i2c/chips/Kconfig config I2C_DEBUG_CORE bool "I2C Core debugging messages" diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index ba26e6cbe74e..ce5fd620b7dc 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o obj-$(CONFIG_I2C) += i2c-core.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o -obj-y += busses/ chips/ algos/ +obj-y += busses/ algos/ ifeq ($(CONFIG_I2C_DEBUG_CORE),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig deleted file mode 100644 index ae4539d99bef..000000000000 --- a/drivers/i2c/chips/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# -# Miscellaneous I2C chip drivers configuration -# -# *** DEPRECATED! Do not add new entries! See Makefile *** -# - -menu "Miscellaneous I2C Chip support" - -config SENSORS_TSL2550 - tristate "Taos TSL2550 ambient light sensor" - depends on EXPERIMENTAL - help - If you say yes here you get support for the Taos TSL2550 - ambient light sensor. - - This driver can also be built as a module. If so, the module - will be called tsl2550. - -endmenu diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile deleted file mode 100644 index fe0af0f81f2d..000000000000 --- a/drivers/i2c/chips/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# -# Makefile for miscellaneous I2C chip drivers. -# -# Do not add new drivers to this directory! It is DEPRECATED. -# -# Device drivers are better grouped according to the functionality they -# implement rather than to the bus they are connected to. In particular: -# * Hardware monitoring chip drivers go to drivers/hwmon -# * RTC chip drivers go to drivers/rtc -# * I/O expander drivers go to drivers/gpio -# - -obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o - -ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) -EXTRA_CFLAGS += -DDEBUG -endif - diff --git a/include/linux/als_sys.h b/include/linux/als_sys.h new file mode 100644 index 000000000000..41793f7acebf --- /dev/null +++ b/include/linux/als_sys.h @@ -0,0 +1,35 @@ +/* + * als_sys.h + * + * Copyright (C) 2009 Intel Corp + * Copyright (C) 2009 Zhang Rui <rui.zhang@intel.com> + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#ifndef __ALS_SYS_H__ +#define __ALS_SYS_H__ + +#include <linux/device.h> + +#define ALS_ILLUMINANCE_MIN 0 +#define ALS_ILLUMINANCE_MAX -1 + +struct device *als_device_register(struct device *dev); +void als_device_unregister(struct device *dev); + +#endif /* __ALS_SYS_H__ */ |