All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] [PATCH v3 1/2] introduce ALS sysfs class
@ 2009-08-19  8:40 ` Zhang Rui
  0 siblings, 0 replies; 9+ messages in thread
From: Zhang Rui @ 2009-08-19  8:40 UTC (permalink / raw)
  To: Linux Kernel Mailing List, linux-acpi
  Cc: Greg KH, Bjorn Helgaas, Pavel Machek, Len Brown, Zhang, Rui

Introduce ALS sysfs class device.

ALS sysfs class device provides a standard sysfs interface
for Ambient Light Sensor devices.

please read Documentation/ABI/testing/sysfs-class-als for detailed sysfs
designs.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 Documentation/ABI/testing/sysfs-class-als |  137 ++++++++++++++++
 drivers/Kconfig                           |    2 
 drivers/Makefile                          |    1 
 drivers/als/Kconfig                       |   10 +
 drivers/als/Makefile                      |    5 
 drivers/als/als_sys.c                     |  256 ++++++++++++++++++++++++++++++
 include/linux/als_sys.h                   |   57 ++++++
 7 files changed, 468 insertions(+)

Index: linux-2.6/drivers/Kconfig
===================================================================
--- linux-2.6.orig/drivers/Kconfig
+++ linux-2.6/drivers/Kconfig
@@ -62,6 +62,8 @@ source "drivers/power/Kconfig"
 
 source "drivers/hwmon/Kconfig"
 
+source "drivers/als/Kconfig"
+
 source "drivers/thermal/Kconfig"
 
 source "drivers/watchdog/Kconfig"
Index: linux-2.6/drivers/Makefile
===================================================================
--- linux-2.6.orig/drivers/Makefile
+++ linux-2.6/drivers/Makefile
@@ -76,6 +76,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/
Index: linux-2.6/drivers/als/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/Kconfig
@@ -0,0 +1,10 @@
+#
+# Ambient Light Sensor sysfs device configuration
+#
+
+menuconfig ALS
+	tristate "Ambient Light Sensor sysfs device"
+	help
+	  This framework provides a generic sysfs interface for
+	  Ambient Light Sensor devices.
+	  If you want this support, you should say Y or M here.
Index: linux-2.6/drivers/als/Makefile
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for sensor chip drivers.
+#
+
+obj-$(CONFIG_ALS)		+= als_sys.o
Index: linux-2.6/drivers/als/als_sys.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/als_sys.c
@@ -0,0 +1,256 @@
+/*
+ *  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/als_sys.h>
+
+MODULE_AUTHOR("Zhang Rui");
+MODULE_DESCRIPTION("Ambient Light Sensor sysfs support");
+MODULE_LICENSE("GPL");
+
+struct als_mapping_item {
+	struct kobject kobj;
+	int index;
+	struct list_head node;
+};
+
+/* sys I/F for Ambient Light Sensor */
+
+#define to_als_device(dev) container_of(dev, struct als_device, device)
+
+static ssize_t
+desc_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct als_device *als = to_als_device(dev);
+
+	return sprintf(buf, "%s\n", als->desc ? als->desc : "N/A");
+}
+
+static ssize_t
+illuminance_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct als_device *als = to_als_device(dev);
+	int illuminance;
+	int result;
+
+	result = als->ops->get_illuminance(als, &illuminance);
+	if (result)
+		return result;
+
+	if (!illuminance)
+		return sprintf(buf, "Illuminance below the supported range\n");
+	else if (illuminance == -1)
+		return sprintf(buf, "Illuminance above the supported range\n");
+	else if (illuminance < -1)
+		return -ERANGE;
+	else
+		return sprintf(buf, "%d\n", illuminance);
+}
+
+static struct device_attribute als_attrs[] = {
+	__ATTR(desc, 0444, desc_show, NULL),
+	__ATTR(illuminance, 0444, illuminance_show, NULL),
+	__ATTR_NULL,
+};
+
+static void als_release(struct device *dev)
+{
+	struct als_device *als = to_als_device(dev);
+	struct als_mapping_item *pos, *n;
+
+	if (als->desc)
+		kfree(als->desc);
+	list_for_each_entry_safe(pos, n, &als->mappings, node){
+		list_del(&pos->node);
+		kfree(pos);
+	}
+	kfree(als);
+}
+
+static struct class als_class = {
+	.name = "als",
+	.dev_release = als_release,
+	.dev_attrs = als_attrs,
+};
+
+#define ATTR(_name, _mode)      \
+	struct attribute als_##_name##_attr = {               \
+	.name = __stringify(_name), .mode = _mode, \
+	};
+
+static ATTR(illuminance, 0444);
+static ATTR(adjustment, 0444);
+
+static struct attribute * als_mapping_attrs[] = {
+	&als_illuminance_attr,
+	&als_adjustment_attr,
+	NULL,
+};
+
+static ssize_t show_mapping_info(struct kobject *kobj,
+				       struct attribute *attr, char *buf)
+{
+	struct device *dev = container_of(kobj->parent, struct device, kobj);
+	struct als_device *als = to_als_device(dev);
+	int index, illuminance, adjustment;
+	int result;
+
+	if (!sscanf(kobj->name, "mapping%d", &index))
+		return -EINVAL;
+
+	result = als->ops->get_mapping_info(als, index, &illuminance, &adjustment);
+	if (result)
+		return result;
+
+	return sprintf(buf, "%u\n", (attr == &als_illuminance_attr) ? illuminance : adjustment);
+}
+
+static struct sysfs_ops als_mapping_info_ops = {
+	.show = show_mapping_info,
+	.store = NULL,
+};
+
+static struct kobj_type als_mapping_ktype = {
+	.sysfs_ops = &als_mapping_info_ops,
+	.default_attrs = als_mapping_attrs,
+};
+
+/**
+ * als_device_update_mappings - update the ambient light illuminance to
+ * 				display luminance adjustment mappings
+ */
+int als_device_update_mappings(struct als_device *als, int count)
+{
+	int old_count = als->count;
+	int i;
+	struct als_mapping_item *pos, *next;
+	int result;
+
+	als->count = count;
+	if (old_count == als->count)
+		return 0;
+
+	mutex_lock(&als->lock);
+	if (als->count > old_count)
+		for (i = old_count; i < als->count; i++) {
+			pos = kzalloc(sizeof(struct als_mapping_item), GFP_KERNEL);
+			if (!pos)
+				return -ENOMEM;
+
+			pos->index = i;
+			result = kobject_init_and_add(&pos->kobj, &als_mapping_ktype,
+					&als->device.kobj, "mapping%d", pos->index);
+			if (result)
+				break;
+			list_add_tail(&pos->node, &als->mappings);
+		}
+	else
+		list_for_each_entry_safe(pos, next, &als->mappings, node) {
+			if (pos->index < als->count)
+				continue;
+			list_del(&pos->node);
+			kobject_put(&pos->kobj);
+			kfree(pos);
+		}
+
+	if (result)
+		als->count = i;
+	mutex_unlock(&als->lock);
+	return 0;
+}
+
+EXPORT_SYMBOL(als_device_update_mappings);
+
+/**
+ * als_device_register - register a new Ambient Light Sensor class device
+ * @ops:	standard ALS devices callbacks.
+ * @devdata:	device private data.
+ */
+struct als_device *als_device_register(struct als_device_ops *ops,
+				       char *desc, void *devdata)
+{
+	struct als_device *als;
+	static int als_id;
+	int result;
+
+	if (!ops || !ops->get_illuminance)
+		return ERR_PTR(-EINVAL);
+
+	als = kzalloc(sizeof(struct als_device), GFP_KERNEL);
+	if (!als)
+		return ERR_PTR(-ENOMEM);
+
+	als->ops = ops;
+	als->device.class = &als_class;
+	als->devdata = devdata;
+	als->id = als_id++;
+	INIT_LIST_HEAD(&als->mappings);
+	mutex_init(&als->lock);
+	if (desc) {
+		als->desc = kzalloc(strlen(desc), GFP_KERNEL);
+		if (!als->desc) {
+			kfree(als);
+			return ERR_PTR(-ENOMEM);
+		}
+		strcpy(als->desc, desc);
+	}
+	dev_set_name(&als->device, "als%d", als->id);
+	result = device_register(&als->device);
+	if (result) {
+		if (als->desc)
+			kfree(als->desc);
+		kfree(als);
+		return ERR_PTR(result);
+	}
+
+	return als;
+}
+
+EXPORT_SYMBOL(als_device_register);
+
+/**
+ * als_device_unregister - removes the registered ALS device
+ * @als:	the ALS device to remove.
+ */
+void als_device_unregister(struct als_device *als)
+{
+	device_unregister(&als->device);
+}
+
+EXPORT_SYMBOL(als_device_unregister);
+
+static int __init als_init(void)
+{
+	return class_register(&als_class);
+}
+
+static void __exit als_exit(void)
+{
+	class_unregister(&als_class);
+}
+
+subsys_initcall(als_init);
+module_exit(als_exit);
Index: linux-2.6/include/linux/als_sys.h
===================================================================
--- /dev/null
+++ linux-2.6/include/linux/als_sys.h
@@ -0,0 +1,57 @@
+/*
+ *  als.h  ($Revision: 0 $)
+ *
+ *  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>
+
+struct als_device;
+
+struct als_device_ops {
+	int (*get_illuminance) (struct als_device *, int *);
+	int (*get_mapping_info) (struct als_device *, int, int *, int *);
+};
+
+struct als_mapping {
+	int illuminance;
+	int adjustment;
+};
+
+struct als_device {
+	int id;
+	int illuminance;
+	struct device device;
+	struct als_device_ops *ops;
+	void *devdata;
+	char *desc;
+	int count;
+	struct list_head mappings;
+	struct mutex lock;
+};
+
+int als_device_update_mappings(struct als_device *, int);
+struct als_device *als_device_register(struct als_device_ops *, char *, void *);
+void als_device_unregister(struct als_device *);
+
+#endif /* __ALS_SYS_H__ */
Index: linux-2.6/Documentation/ABI/testing/sysfs-class-als
===================================================================
--- /dev/null
+++ linux-2.6/Documentation/ABI/testing/sysfs-class-als
@@ -0,0 +1,137 @@
+Ambient Light Sensor Sysfs driver How To
+=========================
+
+Written by Zhang Rui <rui.zhang@intel.com>
+
+Updated: 6 August 2009
+
+Copyright (c)  2009 Intel Corporation
+
+0. Introduction
+
+The generic Ambient Light Sensor sysfs provides a standard interface for ALS devices.
+
+User space can use this interface to get the status of the ambient light environment
+the system is currently in, and get the ambient light illuminance to display luminance
+mappings to calibrate its ambient light policy for a given sensor configuration.
+
+An intelligent ALS application can make ambient light decisions based on inputs
+from these ALS attributes and adjust the LVDS brightness levels.
+
+[0-N]	denotes any positive number starting from 0 to N
+
+Two acronyms that used in this HOW TO only:
+ALI	ambient light illuminace
+DLA	display luminance adjustment (or display brightness adjustment)
+
+1. Ambient Light Sensor sysfs driver interface functions
+
+1.1 struct als_device *als_device_register(struct als_device_ops *ops, char *desc, void *devdata)
+
+	This interface function adds a new ALS device to
+	/sys/class/als folder as als[0-*].
+
+	ops:	thermal zone device call-backs.
+		.get_illuminance: get the current ALI.
+		.get_mappings_count: get the number of ALI to DLA mappings.
+		.get_mapping_info: get the info of a specified ALI to DLA mapping.
+	desc:	a description of the ALS device.
+	devdata:device private data
+
+1.2 void als_device_unregister(struct als_device *als)
+
+	This interface function removes the ALS device.
+	It deletes the corresponding entry form /sys/class/als folder.
+
+1.3 int als_device_update_mappings(struct als_device *als)
+
+	This interface updates the ALI to DLA mappings.
+	This is usually invoked by the native ALS driver when it detects a mapping change.
+
+2. sysfs attributes structure
+
+RO	read only value
+RW	read/write value
+
+ALS sysfs attributes will be represented under /sys/class/als.
+
+/sys/class/als/als[0-*]:
+	|-----desc:			Strings which describes the ALS device
+	|-----illuminance:		Current ALI
+	|-----mapping[0-*]:
+		|-----illuminance:	ALI threshold when an DLA is needed
+		|-----adjustment:	how to do the DLA when the threshold is hit
+
+***********************************
+* Ambient Light Sendor attributes *
+***********************************
+
+desc				Strings which descibes the current ALS.
+				This is given by native ALS driver as part of registration.
+				e.g: "acpi_als" for ACPI ALS devices.
+				RO
+				Required
+
+illuminance			Current ALI reported by native ALS driver
+				Unit: lux (lumens per square meter)
+				RO
+				Required
+
+mapping[0-*]			represent one item of the ALI to DLA mappings.
+
+mapping[0-*]/illuminance	ALI threshold when an DLA is needed
+				RO
+
+mapping[0-*]/adjustment		a relative percentages in order simplify the means
+				by which these adjustments are applied in lieu of
+				changes to the user’s display brightness preference.
+				A value of 100 is used to indicate no (0%) display
+				brightness adjustment.
+				Values less than 100 indicate a negative adjustment
+				(dimming); values greater than 100 indicate a positive
+				adjustment (brightening).
+				RO
+
+3. How to implement ALS control in user space
+
+To implement the ALS control, including both ALI detection and Backlight
+adjustment, interactions between backlight driver and als driver are needed.
+It's ugly to implement such a driver in Linux kernel.
+A user space application is preferred in this case.
+
+Below is a simple example of how to do ALS management in user space.
+
+This is the ACPI backlight sysfs I/F
+/sys/class/backlight/acpi_video0:
+	|-----brightness	6
+	|-----actual_brightness	6
+	|-----max_brightness	10
+
+And this is the ACPI ALS sysfs I/F
+/sys/class/als/als0:
+	|-----illuminance		500
+	|-----mapping[0]
+		|-----illuminance	0
+		|-----adjustment	50
+	|-----mapping[1]
+		|-----illuminance	200
+		|-----adjustment	70
+	|-----mapping[2]
+		|-----illuminance	600
+		|-----adjustment	100
+	|-----mapping[3]
+		|-----illuminance	900
+		|-----adjustment	125
+	|-----mapping[4]
+		|-----illuminance	1200
+		|-----adjustment	150
+
+If user thinks that brightness level 6 is good enough for him when ALI is 600,
+he can set brightness 6 as the user’s display brightness preference.
+When user goes to the basement with the laptop and the ALI changes to 200,
+the ALS application knows that it should do a -25% display brightness
+adjustment, i.e. changes the backlight to 4.
+And when the laptop is used outdoors, where the ALI reaches 1200,
+the ALS application should do a +50% adjustment,
+i.e. run "echo 9 > /sys/class/backlight/acpi_video0/brightness".
+


--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFC] [PATCH v3 1/2] introduce ALS sysfs class
@ 2009-08-19  8:40 ` Zhang Rui
  0 siblings, 0 replies; 9+ messages in thread
From: Zhang Rui @ 2009-08-19  8:40 UTC (permalink / raw)
  To: Linux Kernel Mailing List, linux-acpi
  Cc: Greg KH, Bjorn Helgaas, Pavel Machek, Len Brown, Zhang, Rui

Introduce ALS sysfs class device.

ALS sysfs class device provides a standard sysfs interface
for Ambient Light Sensor devices.

please read Documentation/ABI/testing/sysfs-class-als for detailed sysfs
designs.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 Documentation/ABI/testing/sysfs-class-als |  137 ++++++++++++++++
 drivers/Kconfig                           |    2 
 drivers/Makefile                          |    1 
 drivers/als/Kconfig                       |   10 +
 drivers/als/Makefile                      |    5 
 drivers/als/als_sys.c                     |  256 ++++++++++++++++++++++++++++++
 include/linux/als_sys.h                   |   57 ++++++
 7 files changed, 468 insertions(+)

Index: linux-2.6/drivers/Kconfig
===================================================================
--- linux-2.6.orig/drivers/Kconfig
+++ linux-2.6/drivers/Kconfig
@@ -62,6 +62,8 @@ source "drivers/power/Kconfig"
 
 source "drivers/hwmon/Kconfig"
 
+source "drivers/als/Kconfig"
+
 source "drivers/thermal/Kconfig"
 
 source "drivers/watchdog/Kconfig"
Index: linux-2.6/drivers/Makefile
===================================================================
--- linux-2.6.orig/drivers/Makefile
+++ linux-2.6/drivers/Makefile
@@ -76,6 +76,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/
Index: linux-2.6/drivers/als/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/Kconfig
@@ -0,0 +1,10 @@
+#
+# Ambient Light Sensor sysfs device configuration
+#
+
+menuconfig ALS
+	tristate "Ambient Light Sensor sysfs device"
+	help
+	  This framework provides a generic sysfs interface for
+	  Ambient Light Sensor devices.
+	  If you want this support, you should say Y or M here.
Index: linux-2.6/drivers/als/Makefile
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for sensor chip drivers.
+#
+
+obj-$(CONFIG_ALS)		+= als_sys.o
Index: linux-2.6/drivers/als/als_sys.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/als_sys.c
@@ -0,0 +1,256 @@
+/*
+ *  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/als_sys.h>
+
+MODULE_AUTHOR("Zhang Rui");
+MODULE_DESCRIPTION("Ambient Light Sensor sysfs support");
+MODULE_LICENSE("GPL");
+
+struct als_mapping_item {
+	struct kobject kobj;
+	int index;
+	struct list_head node;
+};
+
+/* sys I/F for Ambient Light Sensor */
+
+#define to_als_device(dev) container_of(dev, struct als_device, device)
+
+static ssize_t
+desc_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct als_device *als = to_als_device(dev);
+
+	return sprintf(buf, "%s\n", als->desc ? als->desc : "N/A");
+}
+
+static ssize_t
+illuminance_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct als_device *als = to_als_device(dev);
+	int illuminance;
+	int result;
+
+	result = als->ops->get_illuminance(als, &illuminance);
+	if (result)
+		return result;
+
+	if (!illuminance)
+		return sprintf(buf, "Illuminance below the supported range\n");
+	else if (illuminance == -1)
+		return sprintf(buf, "Illuminance above the supported range\n");
+	else if (illuminance < -1)
+		return -ERANGE;
+	else
+		return sprintf(buf, "%d\n", illuminance);
+}
+
+static struct device_attribute als_attrs[] = {
+	__ATTR(desc, 0444, desc_show, NULL),
+	__ATTR(illuminance, 0444, illuminance_show, NULL),
+	__ATTR_NULL,
+};
+
+static void als_release(struct device *dev)
+{
+	struct als_device *als = to_als_device(dev);
+	struct als_mapping_item *pos, *n;
+
+	if (als->desc)
+		kfree(als->desc);
+	list_for_each_entry_safe(pos, n, &als->mappings, node){
+		list_del(&pos->node);
+		kfree(pos);
+	}
+	kfree(als);
+}
+
+static struct class als_class = {
+	.name = "als",
+	.dev_release = als_release,
+	.dev_attrs = als_attrs,
+};
+
+#define ATTR(_name, _mode)      \
+	struct attribute als_##_name##_attr = {               \
+	.name = __stringify(_name), .mode = _mode, \
+	};
+
+static ATTR(illuminance, 0444);
+static ATTR(adjustment, 0444);
+
+static struct attribute * als_mapping_attrs[] = {
+	&als_illuminance_attr,
+	&als_adjustment_attr,
+	NULL,
+};
+
+static ssize_t show_mapping_info(struct kobject *kobj,
+				       struct attribute *attr, char *buf)
+{
+	struct device *dev = container_of(kobj->parent, struct device, kobj);
+	struct als_device *als = to_als_device(dev);
+	int index, illuminance, adjustment;
+	int result;
+
+	if (!sscanf(kobj->name, "mapping%d", &index))
+		return -EINVAL;
+
+	result = als->ops->get_mapping_info(als, index, &illuminance, &adjustment);
+	if (result)
+		return result;
+
+	return sprintf(buf, "%u\n", (attr == &als_illuminance_attr) ? illuminance : adjustment);
+}
+
+static struct sysfs_ops als_mapping_info_ops = {
+	.show = show_mapping_info,
+	.store = NULL,
+};
+
+static struct kobj_type als_mapping_ktype = {
+	.sysfs_ops = &als_mapping_info_ops,
+	.default_attrs = als_mapping_attrs,
+};
+
+/**
+ * als_device_update_mappings - update the ambient light illuminance to
+ * 				display luminance adjustment mappings
+ */
+int als_device_update_mappings(struct als_device *als, int count)
+{
+	int old_count = als->count;
+	int i;
+	struct als_mapping_item *pos, *next;
+	int result;
+
+	als->count = count;
+	if (old_count == als->count)
+		return 0;
+
+	mutex_lock(&als->lock);
+	if (als->count > old_count)
+		for (i = old_count; i < als->count; i++) {
+			pos = kzalloc(sizeof(struct als_mapping_item), GFP_KERNEL);
+			if (!pos)
+				return -ENOMEM;
+
+			pos->index = i;
+			result = kobject_init_and_add(&pos->kobj, &als_mapping_ktype,
+					&als->device.kobj, "mapping%d", pos->index);
+			if (result)
+				break;
+			list_add_tail(&pos->node, &als->mappings);
+		}
+	else
+		list_for_each_entry_safe(pos, next, &als->mappings, node) {
+			if (pos->index < als->count)
+				continue;
+			list_del(&pos->node);
+			kobject_put(&pos->kobj);
+			kfree(pos);
+		}
+
+	if (result)
+		als->count = i;
+	mutex_unlock(&als->lock);
+	return 0;
+}
+
+EXPORT_SYMBOL(als_device_update_mappings);
+
+/**
+ * als_device_register - register a new Ambient Light Sensor class device
+ * @ops:	standard ALS devices callbacks.
+ * @devdata:	device private data.
+ */
+struct als_device *als_device_register(struct als_device_ops *ops,
+				       char *desc, void *devdata)
+{
+	struct als_device *als;
+	static int als_id;
+	int result;
+
+	if (!ops || !ops->get_illuminance)
+		return ERR_PTR(-EINVAL);
+
+	als = kzalloc(sizeof(struct als_device), GFP_KERNEL);
+	if (!als)
+		return ERR_PTR(-ENOMEM);
+
+	als->ops = ops;
+	als->device.class = &als_class;
+	als->devdata = devdata;
+	als->id = als_id++;
+	INIT_LIST_HEAD(&als->mappings);
+	mutex_init(&als->lock);
+	if (desc) {
+		als->desc = kzalloc(strlen(desc), GFP_KERNEL);
+		if (!als->desc) {
+			kfree(als);
+			return ERR_PTR(-ENOMEM);
+		}
+		strcpy(als->desc, desc);
+	}
+	dev_set_name(&als->device, "als%d", als->id);
+	result = device_register(&als->device);
+	if (result) {
+		if (als->desc)
+			kfree(als->desc);
+		kfree(als);
+		return ERR_PTR(result);
+	}
+
+	return als;
+}
+
+EXPORT_SYMBOL(als_device_register);
+
+/**
+ * als_device_unregister - removes the registered ALS device
+ * @als:	the ALS device to remove.
+ */
+void als_device_unregister(struct als_device *als)
+{
+	device_unregister(&als->device);
+}
+
+EXPORT_SYMBOL(als_device_unregister);
+
+static int __init als_init(void)
+{
+	return class_register(&als_class);
+}
+
+static void __exit als_exit(void)
+{
+	class_unregister(&als_class);
+}
+
+subsys_initcall(als_init);
+module_exit(als_exit);
Index: linux-2.6/include/linux/als_sys.h
===================================================================
--- /dev/null
+++ linux-2.6/include/linux/als_sys.h
@@ -0,0 +1,57 @@
+/*
+ *  als.h  ($Revision: 0 $)
+ *
+ *  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>
+
+struct als_device;
+
+struct als_device_ops {
+	int (*get_illuminance) (struct als_device *, int *);
+	int (*get_mapping_info) (struct als_device *, int, int *, int *);
+};
+
+struct als_mapping {
+	int illuminance;
+	int adjustment;
+};
+
+struct als_device {
+	int id;
+	int illuminance;
+	struct device device;
+	struct als_device_ops *ops;
+	void *devdata;
+	char *desc;
+	int count;
+	struct list_head mappings;
+	struct mutex lock;
+};
+
+int als_device_update_mappings(struct als_device *, int);
+struct als_device *als_device_register(struct als_device_ops *, char *, void *);
+void als_device_unregister(struct als_device *);
+
+#endif /* __ALS_SYS_H__ */
Index: linux-2.6/Documentation/ABI/testing/sysfs-class-als
===================================================================
--- /dev/null
+++ linux-2.6/Documentation/ABI/testing/sysfs-class-als
@@ -0,0 +1,137 @@
+Ambient Light Sensor Sysfs driver How To
+=========================
+
+Written by Zhang Rui <rui.zhang@intel.com>
+
+Updated: 6 August 2009
+
+Copyright (c)  2009 Intel Corporation
+
+0. Introduction
+
+The generic Ambient Light Sensor sysfs provides a standard interface for ALS devices.
+
+User space can use this interface to get the status of the ambient light environment
+the system is currently in, and get the ambient light illuminance to display luminance
+mappings to calibrate its ambient light policy for a given sensor configuration.
+
+An intelligent ALS application can make ambient light decisions based on inputs
+from these ALS attributes and adjust the LVDS brightness levels.
+
+[0-N]	denotes any positive number starting from 0 to N
+
+Two acronyms that used in this HOW TO only:
+ALI	ambient light illuminace
+DLA	display luminance adjustment (or display brightness adjustment)
+
+1. Ambient Light Sensor sysfs driver interface functions
+
+1.1 struct als_device *als_device_register(struct als_device_ops *ops, char *desc, void *devdata)
+
+	This interface function adds a new ALS device to
+	/sys/class/als folder as als[0-*].
+
+	ops:	thermal zone device call-backs.
+		.get_illuminance: get the current ALI.
+		.get_mappings_count: get the number of ALI to DLA mappings.
+		.get_mapping_info: get the info of a specified ALI to DLA mapping.
+	desc:	a description of the ALS device.
+	devdata:device private data
+
+1.2 void als_device_unregister(struct als_device *als)
+
+	This interface function removes the ALS device.
+	It deletes the corresponding entry form /sys/class/als folder.
+
+1.3 int als_device_update_mappings(struct als_device *als)
+
+	This interface updates the ALI to DLA mappings.
+	This is usually invoked by the native ALS driver when it detects a mapping change.
+
+2. sysfs attributes structure
+
+RO	read only value
+RW	read/write value
+
+ALS sysfs attributes will be represented under /sys/class/als.
+
+/sys/class/als/als[0-*]:
+	|-----desc:			Strings which describes the ALS device
+	|-----illuminance:		Current ALI
+	|-----mapping[0-*]:
+		|-----illuminance:	ALI threshold when an DLA is needed
+		|-----adjustment:	how to do the DLA when the threshold is hit
+
+***********************************
+* Ambient Light Sendor attributes *
+***********************************
+
+desc				Strings which descibes the current ALS.
+				This is given by native ALS driver as part of registration.
+				e.g: "acpi_als" for ACPI ALS devices.
+				RO
+				Required
+
+illuminance			Current ALI reported by native ALS driver
+				Unit: lux (lumens per square meter)
+				RO
+				Required
+
+mapping[0-*]			represent one item of the ALI to DLA mappings.
+
+mapping[0-*]/illuminance	ALI threshold when an DLA is needed
+				RO
+
+mapping[0-*]/adjustment		a relative percentages in order simplify the means
+				by which these adjustments are applied in lieu of
+				changes to the user’s display brightness preference.
+				A value of 100 is used to indicate no (0%) display
+				brightness adjustment.
+				Values less than 100 indicate a negative adjustment
+				(dimming); values greater than 100 indicate a positive
+				adjustment (brightening).
+				RO
+
+3. How to implement ALS control in user space
+
+To implement the ALS control, including both ALI detection and Backlight
+adjustment, interactions between backlight driver and als driver are needed.
+It's ugly to implement such a driver in Linux kernel.
+A user space application is preferred in this case.
+
+Below is a simple example of how to do ALS management in user space.
+
+This is the ACPI backlight sysfs I/F
+/sys/class/backlight/acpi_video0:
+	|-----brightness	6
+	|-----actual_brightness	6
+	|-----max_brightness	10
+
+And this is the ACPI ALS sysfs I/F
+/sys/class/als/als0:
+	|-----illuminance		500
+	|-----mapping[0]
+		|-----illuminance	0
+		|-----adjustment	50
+	|-----mapping[1]
+		|-----illuminance	200
+		|-----adjustment	70
+	|-----mapping[2]
+		|-----illuminance	600
+		|-----adjustment	100
+	|-----mapping[3]
+		|-----illuminance	900
+		|-----adjustment	125
+	|-----mapping[4]
+		|-----illuminance	1200
+		|-----adjustment	150
+
+If user thinks that brightness level 6 is good enough for him when ALI is 600,
+he can set brightness 6 as the user’s display brightness preference.
+When user goes to the basement with the laptop and the ALI changes to 200,
+the ALS application knows that it should do a -25% display brightness
+adjustment, i.e. changes the backlight to 4.
+And when the laptop is used outdoors, where the ALI reaches 1200,
+the ALS application should do a +50% adjustment,
+i.e. run "echo 9 > /sys/class/backlight/acpi_video0/brightness".
+



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC] [PATCH v3 1/2] introduce ALS sysfs class
  2009-08-19  8:40 ` Zhang Rui
@ 2009-08-19  8:57   ` Zhang Rui
  -1 siblings, 0 replies; 9+ messages in thread
From: Zhang Rui @ 2009-08-19  8:57 UTC (permalink / raw)
  To: Linux Kernel Mailing List
  Cc: linux-acpi, Greg KH, Bjorn Helgaas, Pavel Machek, Len Brown

Hi, Pavel,

the current illuminance is not equal to the specified values in the
mappings in most case.
the ALS driver don't have enough knowledge to get a proper display
adjustment, especially that a proper display adjustment would be easy to
select a proper brightness level.
So I think we'd better leave this to user space, which is more flexible.
that's why I still export the mapping info to userspace in this patch.

what do you think?

thanks,
rui

On Wed, 2009-08-19 at 16:40 +0800, Zhang, Rui wrote:
> Introduce ALS sysfs class device.
> 
> ALS sysfs class device provides a standard sysfs interface
> for Ambient Light Sensor devices.
> 
> please read Documentation/ABI/testing/sysfs-class-als for detailed sysfs
> designs.
> 
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> ---
>  Documentation/ABI/testing/sysfs-class-als |  137 ++++++++++++++++
>  drivers/Kconfig                           |    2
>  drivers/Makefile                          |    1
>  drivers/als/Kconfig                       |   10 +
>  drivers/als/Makefile                      |    5
>  drivers/als/als_sys.c                     |  256 ++++++++++++++++++++++++++++++
>  include/linux/als_sys.h                   |   57 ++++++
>  7 files changed, 468 insertions(+)
> 
> Index: linux-2.6/drivers/Kconfig
> ===================================================================
> --- linux-2.6.orig/drivers/Kconfig
> +++ linux-2.6/drivers/Kconfig
> @@ -62,6 +62,8 @@ source "drivers/power/Kconfig"
> 
>  source "drivers/hwmon/Kconfig"
> 
> +source "drivers/als/Kconfig"
> +
>  source "drivers/thermal/Kconfig"
> 
>  source "drivers/watchdog/Kconfig"
> Index: linux-2.6/drivers/Makefile
> ===================================================================
> --- linux-2.6.orig/drivers/Makefile
> +++ linux-2.6/drivers/Makefile
> @@ -76,6 +76,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/
> Index: linux-2.6/drivers/als/Kconfig
> ===================================================================
> --- /dev/null
> +++ linux-2.6/drivers/als/Kconfig
> @@ -0,0 +1,10 @@
> +#
> +# Ambient Light Sensor sysfs device configuration
> +#
> +
> +menuconfig ALS
> +       tristate "Ambient Light Sensor sysfs device"
> +       help
> +         This framework provides a generic sysfs interface for
> +         Ambient Light Sensor devices.
> +         If you want this support, you should say Y or M here.
> Index: linux-2.6/drivers/als/Makefile
> ===================================================================
> --- /dev/null
> +++ linux-2.6/drivers/als/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for sensor chip drivers.
> +#
> +
> +obj-$(CONFIG_ALS)              += als_sys.o
> Index: linux-2.6/drivers/als/als_sys.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6/drivers/als/als_sys.c
> @@ -0,0 +1,256 @@
> +/*
> + *  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/als_sys.h>
> +
> +MODULE_AUTHOR("Zhang Rui");
> +MODULE_DESCRIPTION("Ambient Light Sensor sysfs support");
> +MODULE_LICENSE("GPL");
> +
> +struct als_mapping_item {
> +       struct kobject kobj;
> +       int index;
> +       struct list_head node;
> +};
> +
> +/* sys I/F for Ambient Light Sensor */
> +
> +#define to_als_device(dev) container_of(dev, struct als_device, device)
> +
> +static ssize_t
> +desc_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +       struct als_device *als = to_als_device(dev);
> +
> +       return sprintf(buf, "%s\n", als->desc ? als->desc : "N/A");
> +}
> +
> +static ssize_t
> +illuminance_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +       struct als_device *als = to_als_device(dev);
> +       int illuminance;
> +       int result;
> +
> +       result = als->ops->get_illuminance(als, &illuminance);
> +       if (result)
> +               return result;
> +
> +       if (!illuminance)
> +               return sprintf(buf, "Illuminance below the supported range\n");
> +       else if (illuminance == -1)
> +               return sprintf(buf, "Illuminance above the supported range\n");
> +       else if (illuminance < -1)
> +               return -ERANGE;
> +       else
> +               return sprintf(buf, "%d\n", illuminance);
> +}
> +
> +static struct device_attribute als_attrs[] = {
> +       __ATTR(desc, 0444, desc_show, NULL),
> +       __ATTR(illuminance, 0444, illuminance_show, NULL),
> +       __ATTR_NULL,
> +};
> +
> +static void als_release(struct device *dev)
> +{
> +       struct als_device *als = to_als_device(dev);
> +       struct als_mapping_item *pos, *n;
> +
> +       if (als->desc)
> +               kfree(als->desc);
> +       list_for_each_entry_safe(pos, n, &als->mappings, node){
> +               list_del(&pos->node);
> +               kfree(pos);
> +       }
> +       kfree(als);
> +}
> +
> +static struct class als_class = {
> +       .name = "als",
> +       .dev_release = als_release,
> +       .dev_attrs = als_attrs,
> +};
> +
> +#define ATTR(_name, _mode)      \
> +       struct attribute als_##_name##_attr = {               \
> +       .name = __stringify(_name), .mode = _mode, \
> +       };
> +
> +static ATTR(illuminance, 0444);
> +static ATTR(adjustment, 0444);
> +
> +static struct attribute * als_mapping_attrs[] = {
> +       &als_illuminance_attr,
> +       &als_adjustment_attr,
> +       NULL,
> +};
> +
> +static ssize_t show_mapping_info(struct kobject *kobj,
> +                                      struct attribute *attr, char *buf)
> +{
> +       struct device *dev = container_of(kobj->parent, struct device, kobj);
> +       struct als_device *als = to_als_device(dev);
> +       int index, illuminance, adjustment;
> +       int result;
> +
> +       if (!sscanf(kobj->name, "mapping%d", &index))
> +               return -EINVAL;
> +
> +       result = als->ops->get_mapping_info(als, index, &illuminance, &adjustment);
> +       if (result)
> +               return result;
> +
> +       return sprintf(buf, "%u\n", (attr == &als_illuminance_attr) ? illuminance : adjustment);
> +}
> +
> +static struct sysfs_ops als_mapping_info_ops = {
> +       .show = show_mapping_info,
> +       .store = NULL,
> +};
> +
> +static struct kobj_type als_mapping_ktype = {
> +       .sysfs_ops = &als_mapping_info_ops,
> +       .default_attrs = als_mapping_attrs,
> +};
> +
> +/**
> + * als_device_update_mappings - update the ambient light illuminance to
> + *                             display luminance adjustment mappings
> + */
> +int als_device_update_mappings(struct als_device *als, int count)
> +{
> +       int old_count = als->count;
> +       int i;
> +       struct als_mapping_item *pos, *next;
> +       int result;
> +
> +       als->count = count;
> +       if (old_count == als->count)
> +               return 0;
> +
> +       mutex_lock(&als->lock);
> +       if (als->count > old_count)
> +               for (i = old_count; i < als->count; i++) {
> +                       pos = kzalloc(sizeof(struct als_mapping_item), GFP_KERNEL);
> +                       if (!pos)
> +                               return -ENOMEM;
> +
> +                       pos->index = i;
> +                       result = kobject_init_and_add(&pos->kobj, &als_mapping_ktype,
> +                                       &als->device.kobj, "mapping%d", pos->index);
> +                       if (result)
> +                               break;
> +                       list_add_tail(&pos->node, &als->mappings);
> +               }
> +       else
> +               list_for_each_entry_safe(pos, next, &als->mappings, node) {
> +                       if (pos->index < als->count)
> +                               continue;
> +                       list_del(&pos->node);
> +                       kobject_put(&pos->kobj);
> +                       kfree(pos);
> +               }
> +
> +       if (result)
> +               als->count = i;
> +       mutex_unlock(&als->lock);
> +       return 0;
> +}
> +
> +EXPORT_SYMBOL(als_device_update_mappings);
> +
> +/**
> + * als_device_register - register a new Ambient Light Sensor class device
> + * @ops:       standard ALS devices callbacks.
> + * @devdata:   device private data.
> + */
> +struct als_device *als_device_register(struct als_device_ops *ops,
> +                                      char *desc, void *devdata)
> +{
> +       struct als_device *als;
> +       static int als_id;
> +       int result;
> +
> +       if (!ops || !ops->get_illuminance)
> +               return ERR_PTR(-EINVAL);
> +
> +       als = kzalloc(sizeof(struct als_device), GFP_KERNEL);
> +       if (!als)
> +               return ERR_PTR(-ENOMEM);
> +
> +       als->ops = ops;
> +       als->device.class = &als_class;
> +       als->devdata = devdata;
> +       als->id = als_id++;
> +       INIT_LIST_HEAD(&als->mappings);
> +       mutex_init(&als->lock);
> +       if (desc) {
> +               als->desc = kzalloc(strlen(desc), GFP_KERNEL);
> +               if (!als->desc) {
> +                       kfree(als);
> +                       return ERR_PTR(-ENOMEM);
> +               }
> +               strcpy(als->desc, desc);
> +       }
> +       dev_set_name(&als->device, "als%d", als->id);
> +       result = device_register(&als->device);
> +       if (result) {
> +               if (als->desc)
> +                       kfree(als->desc);
> +               kfree(als);
> +               return ERR_PTR(result);
> +       }
> +
> +       return als;
> +}
> +
> +EXPORT_SYMBOL(als_device_register);
> +
> +/**
> + * als_device_unregister - removes the registered ALS device
> + * @als:       the ALS device to remove.
> + */
> +void als_device_unregister(struct als_device *als)
> +{
> +       device_unregister(&als->device);
> +}
> +
> +EXPORT_SYMBOL(als_device_unregister);
> +
> +static int __init als_init(void)
> +{
> +       return class_register(&als_class);
> +}
> +
> +static void __exit als_exit(void)
> +{
> +       class_unregister(&als_class);
> +}
> +
> +subsys_initcall(als_init);
> +module_exit(als_exit);
> Index: linux-2.6/include/linux/als_sys.h
> ===================================================================
> --- /dev/null
> +++ linux-2.6/include/linux/als_sys.h
> @@ -0,0 +1,57 @@
> +/*
> + *  als.h  ($Revision: 0 $)
> + *
> + *  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>
> +
> +struct als_device;
> +
> +struct als_device_ops {
> +       int (*get_illuminance) (struct als_device *, int *);
> +       int (*get_mapping_info) (struct als_device *, int, int *, int *);
> +};
> +
> +struct als_mapping {
> +       int illuminance;
> +       int adjustment;
> +};
> +
> +struct als_device {
> +       int id;
> +       int illuminance;
> +       struct device device;
> +       struct als_device_ops *ops;
> +       void *devdata;
> +       char *desc;
> +       int count;
> +       struct list_head mappings;
> +       struct mutex lock;
> +};
> +
> +int als_device_update_mappings(struct als_device *, int);
> +struct als_device *als_device_register(struct als_device_ops *, char *, void *);
> +void als_device_unregister(struct als_device *);
> +
> +#endif /* __ALS_SYS_H__ */
> Index: linux-2.6/Documentation/ABI/testing/sysfs-class-als
> ===================================================================
> --- /dev/null
> +++ linux-2.6/Documentation/ABI/testing/sysfs-class-als
> @@ -0,0 +1,137 @@
> +Ambient Light Sensor Sysfs driver How To
> +=========================
> +
> +Written by Zhang Rui <rui.zhang@intel.com>
> +
> +Updated: 6 August 2009
> +
> +Copyright (c)  2009 Intel Corporation
> +
> +0. Introduction
> +
> +The generic Ambient Light Sensor sysfs provides a standard interface for ALS devices.
> +
> +User space can use this interface to get the status of the ambient light environment
> +the system is currently in, and get the ambient light illuminance to display luminance
> +mappings to calibrate its ambient light policy for a given sensor configuration.
> +
> +An intelligent ALS application can make ambient light decisions based on inputs
> +from these ALS attributes and adjust the LVDS brightness levels.
> +
> +[0-N]  denotes any positive number starting from 0 to N
> +
> +Two acronyms that used in this HOW TO only:
> +ALI    ambient light illuminace
> +DLA    display luminance adjustment (or display brightness adjustment)
> +
> +1. Ambient Light Sensor sysfs driver interface functions
> +
> +1.1 struct als_device *als_device_register(struct als_device_ops *ops, char *desc, void *devdata)
> +
> +       This interface function adds a new ALS device to
> +       /sys/class/als folder as als[0-*].
> +
> +       ops:    thermal zone device call-backs.
> +               .get_illuminance: get the current ALI.
> +               .get_mappings_count: get the number of ALI to DLA mappings.
> +               .get_mapping_info: get the info of a specified ALI to DLA mapping.
> +       desc:   a description of the ALS device.
> +       devdata:device private data
> +
> +1.2 void als_device_unregister(struct als_device *als)
> +
> +       This interface function removes the ALS device.
> +       It deletes the corresponding entry form /sys/class/als folder.
> +
> +1.3 int als_device_update_mappings(struct als_device *als)
> +
> +       This interface updates the ALI to DLA mappings.
> +       This is usually invoked by the native ALS driver when it detects a mapping change.
> +
> +2. sysfs attributes structure
> +
> +RO     read only value
> +RW     read/write value
> +
> +ALS sysfs attributes will be represented under /sys/class/als.
> +
> +/sys/class/als/als[0-*]:
> +       |-----desc:                     Strings which describes the ALS device
> +       |-----illuminance:              Current ALI
> +       |-----mapping[0-*]:
> +               |-----illuminance:      ALI threshold when an DLA is needed
> +               |-----adjustment:       how to do the DLA when the threshold is hit
> +
> +***********************************
> +* Ambient Light Sendor attributes *
> +***********************************
> +
> +desc                           Strings which descibes the current ALS.
> +                               This is given by native ALS driver as part of registration.
> +                               e.g: "acpi_als" for ACPI ALS devices.
> +                               RO
> +                               Required
> +
> +illuminance                    Current ALI reported by native ALS driver
> +                               Unit: lux (lumens per square meter)
> +                               RO
> +                               Required
> +
> +mapping[0-*]                   represent one item of the ALI to DLA mappings.
> +
> +mapping[0-*]/illuminance       ALI threshold when an DLA is needed
> +                               RO
> +
> +mapping[0-*]/adjustment                a relative percentages in order simplify the means
> +                               by which these adjustments are applied in lieu of
> +                               changes to the user’s display brightness preference.
> +                               A value of 100 is used to indicate no (0%) display
> +                               brightness adjustment.
> +                               Values less than 100 indicate a negative adjustment
> +                               (dimming); values greater than 100 indicate a positive
> +                               adjustment (brightening).
> +                               RO
> +
> +3. How to implement ALS control in user space
> +
> +To implement the ALS control, including both ALI detection and Backlight
> +adjustment, interactions between backlight driver and als driver are needed.
> +It's ugly to implement such a driver in Linux kernel.
> +A user space application is preferred in this case.
> +
> +Below is a simple example of how to do ALS management in user space.
> +
> +This is the ACPI backlight sysfs I/F
> +/sys/class/backlight/acpi_video0:
> +       |-----brightness        6
> +       |-----actual_brightness 6
> +       |-----max_brightness    10
> +
> +And this is the ACPI ALS sysfs I/F
> +/sys/class/als/als0:
> +       |-----illuminance               500
> +       |-----mapping[0]
> +               |-----illuminance       0
> +               |-----adjustment        50
> +       |-----mapping[1]
> +               |-----illuminance       200
> +               |-----adjustment        70
> +       |-----mapping[2]
> +               |-----illuminance       600
> +               |-----adjustment        100
> +       |-----mapping[3]
> +               |-----illuminance       900
> +               |-----adjustment        125
> +       |-----mapping[4]
> +               |-----illuminance       1200
> +               |-----adjustment        150
> +
> +If user thinks that brightness level 6 is good enough for him when ALI is 600,
> +he can set brightness 6 as the user’s display brightness preference.
> +When user goes to the basement with the laptop and the ALI changes to 200,
> +the ALS application knows that it should do a -25% display brightness
> +adjustment, i.e. changes the backlight to 4.
> +And when the laptop is used outdoors, where the ALI reaches 1200,
> +the ALS application should do a +50% adjustment,
> +i.e. run "echo 9 > /sys/class/backlight/acpi_video0/brightness".
> +
> 
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC] [PATCH v3 1/2] introduce ALS sysfs class
@ 2009-08-19  8:57   ` Zhang Rui
  0 siblings, 0 replies; 9+ messages in thread
From: Zhang Rui @ 2009-08-19  8:57 UTC (permalink / raw)
  To: Linux Kernel Mailing List
  Cc: linux-acpi, Greg KH, Bjorn Helgaas, Pavel Machek, Len Brown

Hi, Pavel,

the current illuminance is not equal to the specified values in the
mappings in most case.
the ALS driver don't have enough knowledge to get a proper display
adjustment, especially that a proper display adjustment would be easy to
select a proper brightness level.
So I think we'd better leave this to user space, which is more flexible.
that's why I still export the mapping info to userspace in this patch.

what do you think?

thanks,
rui

On Wed, 2009-08-19 at 16:40 +0800, Zhang, Rui wrote:
> Introduce ALS sysfs class device.
> 
> ALS sysfs class device provides a standard sysfs interface
> for Ambient Light Sensor devices.
> 
> please read Documentation/ABI/testing/sysfs-class-als for detailed sysfs
> designs.
> 
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> ---
>  Documentation/ABI/testing/sysfs-class-als |  137 ++++++++++++++++
>  drivers/Kconfig                           |    2
>  drivers/Makefile                          |    1
>  drivers/als/Kconfig                       |   10 +
>  drivers/als/Makefile                      |    5
>  drivers/als/als_sys.c                     |  256 ++++++++++++++++++++++++++++++
>  include/linux/als_sys.h                   |   57 ++++++
>  7 files changed, 468 insertions(+)
> 
> Index: linux-2.6/drivers/Kconfig
> ===================================================================
> --- linux-2.6.orig/drivers/Kconfig
> +++ linux-2.6/drivers/Kconfig
> @@ -62,6 +62,8 @@ source "drivers/power/Kconfig"
> 
>  source "drivers/hwmon/Kconfig"
> 
> +source "drivers/als/Kconfig"
> +
>  source "drivers/thermal/Kconfig"
> 
>  source "drivers/watchdog/Kconfig"
> Index: linux-2.6/drivers/Makefile
> ===================================================================
> --- linux-2.6.orig/drivers/Makefile
> +++ linux-2.6/drivers/Makefile
> @@ -76,6 +76,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/
> Index: linux-2.6/drivers/als/Kconfig
> ===================================================================
> --- /dev/null
> +++ linux-2.6/drivers/als/Kconfig
> @@ -0,0 +1,10 @@
> +#
> +# Ambient Light Sensor sysfs device configuration
> +#
> +
> +menuconfig ALS
> +       tristate "Ambient Light Sensor sysfs device"
> +       help
> +         This framework provides a generic sysfs interface for
> +         Ambient Light Sensor devices.
> +         If you want this support, you should say Y or M here.
> Index: linux-2.6/drivers/als/Makefile
> ===================================================================
> --- /dev/null
> +++ linux-2.6/drivers/als/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for sensor chip drivers.
> +#
> +
> +obj-$(CONFIG_ALS)              += als_sys.o
> Index: linux-2.6/drivers/als/als_sys.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6/drivers/als/als_sys.c
> @@ -0,0 +1,256 @@
> +/*
> + *  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/als_sys.h>
> +
> +MODULE_AUTHOR("Zhang Rui");
> +MODULE_DESCRIPTION("Ambient Light Sensor sysfs support");
> +MODULE_LICENSE("GPL");
> +
> +struct als_mapping_item {
> +       struct kobject kobj;
> +       int index;
> +       struct list_head node;
> +};
> +
> +/* sys I/F for Ambient Light Sensor */
> +
> +#define to_als_device(dev) container_of(dev, struct als_device, device)
> +
> +static ssize_t
> +desc_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +       struct als_device *als = to_als_device(dev);
> +
> +       return sprintf(buf, "%s\n", als->desc ? als->desc : "N/A");
> +}
> +
> +static ssize_t
> +illuminance_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +       struct als_device *als = to_als_device(dev);
> +       int illuminance;
> +       int result;
> +
> +       result = als->ops->get_illuminance(als, &illuminance);
> +       if (result)
> +               return result;
> +
> +       if (!illuminance)
> +               return sprintf(buf, "Illuminance below the supported range\n");
> +       else if (illuminance == -1)
> +               return sprintf(buf, "Illuminance above the supported range\n");
> +       else if (illuminance < -1)
> +               return -ERANGE;
> +       else
> +               return sprintf(buf, "%d\n", illuminance);
> +}
> +
> +static struct device_attribute als_attrs[] = {
> +       __ATTR(desc, 0444, desc_show, NULL),
> +       __ATTR(illuminance, 0444, illuminance_show, NULL),
> +       __ATTR_NULL,
> +};
> +
> +static void als_release(struct device *dev)
> +{
> +       struct als_device *als = to_als_device(dev);
> +       struct als_mapping_item *pos, *n;
> +
> +       if (als->desc)
> +               kfree(als->desc);
> +       list_for_each_entry_safe(pos, n, &als->mappings, node){
> +               list_del(&pos->node);
> +               kfree(pos);
> +       }
> +       kfree(als);
> +}
> +
> +static struct class als_class = {
> +       .name = "als",
> +       .dev_release = als_release,
> +       .dev_attrs = als_attrs,
> +};
> +
> +#define ATTR(_name, _mode)      \
> +       struct attribute als_##_name##_attr = {               \
> +       .name = __stringify(_name), .mode = _mode, \
> +       };
> +
> +static ATTR(illuminance, 0444);
> +static ATTR(adjustment, 0444);
> +
> +static struct attribute * als_mapping_attrs[] = {
> +       &als_illuminance_attr,
> +       &als_adjustment_attr,
> +       NULL,
> +};
> +
> +static ssize_t show_mapping_info(struct kobject *kobj,
> +                                      struct attribute *attr, char *buf)
> +{
> +       struct device *dev = container_of(kobj->parent, struct device, kobj);
> +       struct als_device *als = to_als_device(dev);
> +       int index, illuminance, adjustment;
> +       int result;
> +
> +       if (!sscanf(kobj->name, "mapping%d", &index))
> +               return -EINVAL;
> +
> +       result = als->ops->get_mapping_info(als, index, &illuminance, &adjustment);
> +       if (result)
> +               return result;
> +
> +       return sprintf(buf, "%u\n", (attr == &als_illuminance_attr) ? illuminance : adjustment);
> +}
> +
> +static struct sysfs_ops als_mapping_info_ops = {
> +       .show = show_mapping_info,
> +       .store = NULL,
> +};
> +
> +static struct kobj_type als_mapping_ktype = {
> +       .sysfs_ops = &als_mapping_info_ops,
> +       .default_attrs = als_mapping_attrs,
> +};
> +
> +/**
> + * als_device_update_mappings - update the ambient light illuminance to
> + *                             display luminance adjustment mappings
> + */
> +int als_device_update_mappings(struct als_device *als, int count)
> +{
> +       int old_count = als->count;
> +       int i;
> +       struct als_mapping_item *pos, *next;
> +       int result;
> +
> +       als->count = count;
> +       if (old_count == als->count)
> +               return 0;
> +
> +       mutex_lock(&als->lock);
> +       if (als->count > old_count)
> +               for (i = old_count; i < als->count; i++) {
> +                       pos = kzalloc(sizeof(struct als_mapping_item), GFP_KERNEL);
> +                       if (!pos)
> +                               return -ENOMEM;
> +
> +                       pos->index = i;
> +                       result = kobject_init_and_add(&pos->kobj, &als_mapping_ktype,
> +                                       &als->device.kobj, "mapping%d", pos->index);
> +                       if (result)
> +                               break;
> +                       list_add_tail(&pos->node, &als->mappings);
> +               }
> +       else
> +               list_for_each_entry_safe(pos, next, &als->mappings, node) {
> +                       if (pos->index < als->count)
> +                               continue;
> +                       list_del(&pos->node);
> +                       kobject_put(&pos->kobj);
> +                       kfree(pos);
> +               }
> +
> +       if (result)
> +               als->count = i;
> +       mutex_unlock(&als->lock);
> +       return 0;
> +}
> +
> +EXPORT_SYMBOL(als_device_update_mappings);
> +
> +/**
> + * als_device_register - register a new Ambient Light Sensor class device
> + * @ops:       standard ALS devices callbacks.
> + * @devdata:   device private data.
> + */
> +struct als_device *als_device_register(struct als_device_ops *ops,
> +                                      char *desc, void *devdata)
> +{
> +       struct als_device *als;
> +       static int als_id;
> +       int result;
> +
> +       if (!ops || !ops->get_illuminance)
> +               return ERR_PTR(-EINVAL);
> +
> +       als = kzalloc(sizeof(struct als_device), GFP_KERNEL);
> +       if (!als)
> +               return ERR_PTR(-ENOMEM);
> +
> +       als->ops = ops;
> +       als->device.class = &als_class;
> +       als->devdata = devdata;
> +       als->id = als_id++;
> +       INIT_LIST_HEAD(&als->mappings);
> +       mutex_init(&als->lock);
> +       if (desc) {
> +               als->desc = kzalloc(strlen(desc), GFP_KERNEL);
> +               if (!als->desc) {
> +                       kfree(als);
> +                       return ERR_PTR(-ENOMEM);
> +               }
> +               strcpy(als->desc, desc);
> +       }
> +       dev_set_name(&als->device, "als%d", als->id);
> +       result = device_register(&als->device);
> +       if (result) {
> +               if (als->desc)
> +                       kfree(als->desc);
> +               kfree(als);
> +               return ERR_PTR(result);
> +       }
> +
> +       return als;
> +}
> +
> +EXPORT_SYMBOL(als_device_register);
> +
> +/**
> + * als_device_unregister - removes the registered ALS device
> + * @als:       the ALS device to remove.
> + */
> +void als_device_unregister(struct als_device *als)
> +{
> +       device_unregister(&als->device);
> +}
> +
> +EXPORT_SYMBOL(als_device_unregister);
> +
> +static int __init als_init(void)
> +{
> +       return class_register(&als_class);
> +}
> +
> +static void __exit als_exit(void)
> +{
> +       class_unregister(&als_class);
> +}
> +
> +subsys_initcall(als_init);
> +module_exit(als_exit);
> Index: linux-2.6/include/linux/als_sys.h
> ===================================================================
> --- /dev/null
> +++ linux-2.6/include/linux/als_sys.h
> @@ -0,0 +1,57 @@
> +/*
> + *  als.h  ($Revision: 0 $)
> + *
> + *  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>
> +
> +struct als_device;
> +
> +struct als_device_ops {
> +       int (*get_illuminance) (struct als_device *, int *);
> +       int (*get_mapping_info) (struct als_device *, int, int *, int *);
> +};
> +
> +struct als_mapping {
> +       int illuminance;
> +       int adjustment;
> +};
> +
> +struct als_device {
> +       int id;
> +       int illuminance;
> +       struct device device;
> +       struct als_device_ops *ops;
> +       void *devdata;
> +       char *desc;
> +       int count;
> +       struct list_head mappings;
> +       struct mutex lock;
> +};
> +
> +int als_device_update_mappings(struct als_device *, int);
> +struct als_device *als_device_register(struct als_device_ops *, char *, void *);
> +void als_device_unregister(struct als_device *);
> +
> +#endif /* __ALS_SYS_H__ */
> Index: linux-2.6/Documentation/ABI/testing/sysfs-class-als
> ===================================================================
> --- /dev/null
> +++ linux-2.6/Documentation/ABI/testing/sysfs-class-als
> @@ -0,0 +1,137 @@
> +Ambient Light Sensor Sysfs driver How To
> +=========================
> +
> +Written by Zhang Rui <rui.zhang@intel.com>
> +
> +Updated: 6 August 2009
> +
> +Copyright (c)  2009 Intel Corporation
> +
> +0. Introduction
> +
> +The generic Ambient Light Sensor sysfs provides a standard interface for ALS devices.
> +
> +User space can use this interface to get the status of the ambient light environment
> +the system is currently in, and get the ambient light illuminance to display luminance
> +mappings to calibrate its ambient light policy for a given sensor configuration.
> +
> +An intelligent ALS application can make ambient light decisions based on inputs
> +from these ALS attributes and adjust the LVDS brightness levels.
> +
> +[0-N]  denotes any positive number starting from 0 to N
> +
> +Two acronyms that used in this HOW TO only:
> +ALI    ambient light illuminace
> +DLA    display luminance adjustment (or display brightness adjustment)
> +
> +1. Ambient Light Sensor sysfs driver interface functions
> +
> +1.1 struct als_device *als_device_register(struct als_device_ops *ops, char *desc, void *devdata)
> +
> +       This interface function adds a new ALS device to
> +       /sys/class/als folder as als[0-*].
> +
> +       ops:    thermal zone device call-backs.
> +               .get_illuminance: get the current ALI.
> +               .get_mappings_count: get the number of ALI to DLA mappings.
> +               .get_mapping_info: get the info of a specified ALI to DLA mapping.
> +       desc:   a description of the ALS device.
> +       devdata:device private data
> +
> +1.2 void als_device_unregister(struct als_device *als)
> +
> +       This interface function removes the ALS device.
> +       It deletes the corresponding entry form /sys/class/als folder.
> +
> +1.3 int als_device_update_mappings(struct als_device *als)
> +
> +       This interface updates the ALI to DLA mappings.
> +       This is usually invoked by the native ALS driver when it detects a mapping change.
> +
> +2. sysfs attributes structure
> +
> +RO     read only value
> +RW     read/write value
> +
> +ALS sysfs attributes will be represented under /sys/class/als.
> +
> +/sys/class/als/als[0-*]:
> +       |-----desc:                     Strings which describes the ALS device
> +       |-----illuminance:              Current ALI
> +       |-----mapping[0-*]:
> +               |-----illuminance:      ALI threshold when an DLA is needed
> +               |-----adjustment:       how to do the DLA when the threshold is hit
> +
> +***********************************
> +* Ambient Light Sendor attributes *
> +***********************************
> +
> +desc                           Strings which descibes the current ALS.
> +                               This is given by native ALS driver as part of registration.
> +                               e.g: "acpi_als" for ACPI ALS devices.
> +                               RO
> +                               Required
> +
> +illuminance                    Current ALI reported by native ALS driver
> +                               Unit: lux (lumens per square meter)
> +                               RO
> +                               Required
> +
> +mapping[0-*]                   represent one item of the ALI to DLA mappings.
> +
> +mapping[0-*]/illuminance       ALI threshold when an DLA is needed
> +                               RO
> +
> +mapping[0-*]/adjustment                a relative percentages in order simplify the means
> +                               by which these adjustments are applied in lieu of
> +                               changes to the user’s display brightness preference.
> +                               A value of 100 is used to indicate no (0%) display
> +                               brightness adjustment.
> +                               Values less than 100 indicate a negative adjustment
> +                               (dimming); values greater than 100 indicate a positive
> +                               adjustment (brightening).
> +                               RO
> +
> +3. How to implement ALS control in user space
> +
> +To implement the ALS control, including both ALI detection and Backlight
> +adjustment, interactions between backlight driver and als driver are needed.
> +It's ugly to implement such a driver in Linux kernel.
> +A user space application is preferred in this case.
> +
> +Below is a simple example of how to do ALS management in user space.
> +
> +This is the ACPI backlight sysfs I/F
> +/sys/class/backlight/acpi_video0:
> +       |-----brightness        6
> +       |-----actual_brightness 6
> +       |-----max_brightness    10
> +
> +And this is the ACPI ALS sysfs I/F
> +/sys/class/als/als0:
> +       |-----illuminance               500
> +       |-----mapping[0]
> +               |-----illuminance       0
> +               |-----adjustment        50
> +       |-----mapping[1]
> +               |-----illuminance       200
> +               |-----adjustment        70
> +       |-----mapping[2]
> +               |-----illuminance       600
> +               |-----adjustment        100
> +       |-----mapping[3]
> +               |-----illuminance       900
> +               |-----adjustment        125
> +       |-----mapping[4]
> +               |-----illuminance       1200
> +               |-----adjustment        150
> +
> +If user thinks that brightness level 6 is good enough for him when ALI is 600,
> +he can set brightness 6 as the user’s display brightness preference.
> +When user goes to the basement with the laptop and the ALI changes to 200,
> +the ALS application knows that it should do a -25% display brightness
> +adjustment, i.e. changes the backlight to 4.
> +And when the laptop is used outdoors, where the ALI reaches 1200,
> +the ALS application should do a +50% adjustment,
> +i.e. run "echo 9 > /sys/class/backlight/acpi_video0/brightness".
> +
> 
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC] [PATCH v3 1/2] introduce ALS sysfs class
  2009-08-19  8:40 ` Zhang Rui
  (?)
  (?)
@ 2009-08-19 16:01 ` Greg KH
  2009-08-21  1:54     ` Zhang Rui
  -1 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2009-08-19 16:01 UTC (permalink / raw)
  To: Zhang Rui
  Cc: Linux Kernel Mailing List, linux-acpi, Bjorn Helgaas,
	Pavel Machek, Len Brown

On Wed, Aug 19, 2009 at 04:40:29PM +0800, Zhang Rui wrote:
> --- /dev/null
> +++ linux-2.6/Documentation/ABI/testing/sysfs-class-als
> @@ -0,0 +1,137 @@
> +Ambient Light Sensor Sysfs driver How To
> +=========================

<snip>

While this is a nice document, it does not follow the standard that the
files in Documentation/ABI/ should be in.  Can you please read
Documentation/ABI/README and convert the file to follow that?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC] [PATCH v3 1/2] introduce ALS sysfs class
  2009-08-19 16:01 ` Greg KH
@ 2009-08-21  1:54     ` Zhang Rui
  0 siblings, 0 replies; 9+ messages in thread
From: Zhang Rui @ 2009-08-21  1:54 UTC (permalink / raw)
  To: Greg KH
  Cc: Linux Kernel Mailing List, linux-acpi, Bjorn Helgaas,
	Pavel Machek, Len Brown

On Thu, 2009-08-20 at 00:01 +0800, Greg KH wrote:
> On Wed, Aug 19, 2009 at 04:40:29PM +0800, Zhang Rui wrote:
> > --- /dev/null
> > +++ linux-2.6/Documentation/ABI/testing/sysfs-class-als
> > @@ -0,0 +1,137 @@
> > +Ambient Light Sensor Sysfs driver How To
> > +=========================
> 
> <snip>
> 
> While this is a nice document, it does not follow the standard that the
> files in Documentation/ABI/ should be in.  Can you please read
> Documentation/ABI/README and convert the file to follow that?
> 
sure. done
refreshed patch attached.

Introduce ALS sysfs class device.

ALS sysfs class device provides a standard sysfs interface
for Ambient Light Sensor devices.

please read Documentation/ABI/testing/sysfs-class-als for detailed sysfs
designs.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 Documentation/ABI/testing/sysfs-class-als |   47 +++++
 drivers/Kconfig                           |    2 
 drivers/Makefile                          |    1 
 drivers/als/Kconfig                       |   10 +
 drivers/als/Makefile                      |    5 
 drivers/als/als_sys.c                     |  256 ++++++++++++++++++++++++++++++
 include/linux/als_sys.h                   |   57 ++++++
 7 files changed, 378 insertions(+)

Index: linux-2.6/drivers/Kconfig
===================================================================
--- linux-2.6.orig/drivers/Kconfig
+++ linux-2.6/drivers/Kconfig
@@ -62,6 +62,8 @@ source "drivers/power/Kconfig"
 
 source "drivers/hwmon/Kconfig"
 
+source "drivers/als/Kconfig"
+
 source "drivers/thermal/Kconfig"
 
 source "drivers/watchdog/Kconfig"
Index: linux-2.6/drivers/Makefile
===================================================================
--- linux-2.6.orig/drivers/Makefile
+++ linux-2.6/drivers/Makefile
@@ -76,6 +76,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/
Index: linux-2.6/drivers/als/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/Kconfig
@@ -0,0 +1,10 @@
+#
+# Ambient Light Sensor sysfs device configuration
+#
+
+menuconfig ALS
+	tristate "Ambient Light Sensor sysfs device"
+	help
+	  This framework provides a generic sysfs interface for
+	  Ambient Light Sensor devices.
+	  If you want this support, you should say Y or M here.
Index: linux-2.6/drivers/als/Makefile
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for sensor chip drivers.
+#
+
+obj-$(CONFIG_ALS)		+= als_sys.o
Index: linux-2.6/drivers/als/als_sys.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/als_sys.c
@@ -0,0 +1,256 @@
+/*
+ *  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/als_sys.h>
+
+MODULE_AUTHOR("Zhang Rui");
+MODULE_DESCRIPTION("Ambient Light Sensor sysfs support");
+MODULE_LICENSE("GPL");
+
+struct als_mapping_item {
+	struct kobject kobj;
+	int index;
+	struct list_head node;
+};
+
+/* sys I/F for Ambient Light Sensor */
+
+#define to_als_device(dev) container_of(dev, struct als_device, device)
+
+static ssize_t
+desc_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct als_device *als = to_als_device(dev);
+
+	return sprintf(buf, "%s\n", als->desc ? als->desc : "N/A");
+}
+
+static ssize_t
+illuminance_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct als_device *als = to_als_device(dev);
+	int illuminance;
+	int result;
+
+	result = als->ops->get_illuminance(als, &illuminance);
+	if (result)
+		return result;
+
+	if (!illuminance)
+		return sprintf(buf, "Illuminance below the supported range\n");
+	else if (illuminance == -1)
+		return sprintf(buf, "Illuminance above the supported range\n");
+	else if (illuminance < -1)
+		return -ERANGE;
+	else
+		return sprintf(buf, "%d\n", illuminance);
+}
+
+static struct device_attribute als_attrs[] = {
+	__ATTR(desc, 0444, desc_show, NULL),
+	__ATTR(illuminance, 0444, illuminance_show, NULL),
+	__ATTR_NULL,
+};
+
+static void als_release(struct device *dev)
+{
+	struct als_device *als = to_als_device(dev);
+	struct als_mapping_item *pos, *n;
+
+	if (als->desc)
+		kfree(als->desc);
+	list_for_each_entry_safe(pos, n, &als->mappings, node){
+		list_del(&pos->node);
+		kfree(pos);
+	}
+	kfree(als);
+}
+
+static struct class als_class = {
+	.name = "als",
+	.dev_release = als_release,
+	.dev_attrs = als_attrs,
+};
+
+#define ATTR(_name, _mode)      \
+	struct attribute als_##_name##_attr = {               \
+	.name = __stringify(_name), .mode = _mode, \
+	};
+
+static ATTR(illuminance, 0444);
+static ATTR(adjustment, 0444);
+
+static struct attribute * als_mapping_attrs[] = {
+	&als_illuminance_attr,
+	&als_adjustment_attr,
+	NULL,
+};
+
+static ssize_t show_mapping_info(struct kobject *kobj,
+				       struct attribute *attr, char *buf)
+{
+	struct device *dev = container_of(kobj->parent, struct device, kobj);
+	struct als_device *als = to_als_device(dev);
+	int index, illuminance, adjustment;
+	int result;
+
+	if (!sscanf(kobj->name, "mapping%d", &index))
+		return -EINVAL;
+
+	result = als->ops->get_mapping_info(als, index, &illuminance, &adjustment);
+	if (result)
+		return result;
+
+	return sprintf(buf, "%u\n", (attr == &als_illuminance_attr) ? illuminance : adjustment);
+}
+
+static struct sysfs_ops als_mapping_info_ops = {
+	.show = show_mapping_info,
+	.store = NULL,
+};
+
+static struct kobj_type als_mapping_ktype = {
+	.sysfs_ops = &als_mapping_info_ops,
+	.default_attrs = als_mapping_attrs,
+};
+
+/**
+ * als_device_update_mappings - update the ambient light illuminance to
+ * 				display luminance adjustment mappings
+ */
+int als_device_update_mappings(struct als_device *als, int count)
+{
+	int old_count = als->count;
+	int i;
+	struct als_mapping_item *pos, *next;
+	int result;
+
+	als->count = count;
+	if (old_count == als->count)
+		return 0;
+
+	mutex_lock(&als->lock);
+	if (als->count > old_count)
+		for (i = old_count; i < als->count; i++) {
+			pos = kzalloc(sizeof(struct als_mapping_item), GFP_KERNEL);
+			if (!pos)
+				return -ENOMEM;
+
+			pos->index = i;
+			result = kobject_init_and_add(&pos->kobj, &als_mapping_ktype,
+					&als->device.kobj, "mapping%d", pos->index);
+			if (result)
+				break;
+			list_add_tail(&pos->node, &als->mappings);
+		}
+	else
+		list_for_each_entry_safe(pos, next, &als->mappings, node) {
+			if (pos->index < als->count)
+				continue;
+			list_del(&pos->node);
+			kobject_put(&pos->kobj);
+			kfree(pos);
+		}
+
+	if (result)
+		als->count = i;
+	mutex_unlock(&als->lock);
+	return 0;
+}
+
+EXPORT_SYMBOL(als_device_update_mappings);
+
+/**
+ * als_device_register - register a new Ambient Light Sensor class device
+ * @ops:	standard ALS devices callbacks.
+ * @devdata:	device private data.
+ */
+struct als_device *als_device_register(struct als_device_ops *ops,
+				       char *desc, void *devdata)
+{
+	struct als_device *als;
+	static int als_id;
+	int result;
+
+	if (!ops || !ops->get_illuminance)
+		return ERR_PTR(-EINVAL);
+
+	als = kzalloc(sizeof(struct als_device), GFP_KERNEL);
+	if (!als)
+		return ERR_PTR(-ENOMEM);
+
+	als->ops = ops;
+	als->device.class = &als_class;
+	als->devdata = devdata;
+	als->id = als_id++;
+	INIT_LIST_HEAD(&als->mappings);
+	mutex_init(&als->lock);
+	if (desc) {
+		als->desc = kzalloc(strlen(desc), GFP_KERNEL);
+		if (!als->desc) {
+			kfree(als);
+			return ERR_PTR(-ENOMEM);
+		}
+		strcpy(als->desc, desc);
+	}
+	dev_set_name(&als->device, "als%d", als->id);
+	result = device_register(&als->device);
+	if (result) {
+		if (als->desc)
+			kfree(als->desc);
+		kfree(als);
+		return ERR_PTR(result);
+	}
+
+	return als;
+}
+
+EXPORT_SYMBOL(als_device_register);
+
+/**
+ * als_device_unregister - removes the registered ALS device
+ * @als:	the ALS device to remove.
+ */
+void als_device_unregister(struct als_device *als)
+{
+	device_unregister(&als->device);
+}
+
+EXPORT_SYMBOL(als_device_unregister);
+
+static int __init als_init(void)
+{
+	return class_register(&als_class);
+}
+
+static void __exit als_exit(void)
+{
+	class_unregister(&als_class);
+}
+
+subsys_initcall(als_init);
+module_exit(als_exit);
Index: linux-2.6/include/linux/als_sys.h
===================================================================
--- /dev/null
+++ linux-2.6/include/linux/als_sys.h
@@ -0,0 +1,57 @@
+/*
+ *  als.h  ($Revision: 0 $)
+ *
+ *  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>
+
+struct als_device;
+
+struct als_device_ops {
+	int (*get_illuminance) (struct als_device *, int *);
+	int (*get_mapping_info) (struct als_device *, int, int *, int *);
+};
+
+struct als_mapping {
+	int illuminance;
+	int adjustment;
+};
+
+struct als_device {
+	int id;
+	int illuminance;
+	struct device device;
+	struct als_device_ops *ops;
+	void *devdata;
+	char *desc;
+	int count;
+	struct list_head mappings;
+	struct mutex lock;
+};
+
+int als_device_update_mappings(struct als_device *, int);
+struct als_device *als_device_register(struct als_device_ops *, char *, void *);
+void als_device_unregister(struct als_device *);
+
+#endif /* __ALS_SYS_H__ */
Index: linux-2.6/Documentation/ABI/testing/sysfs-class-als
===================================================================
--- /dev/null
+++ linux-2.6/Documentation/ABI/testing/sysfs-class-als
@@ -0,0 +1,47 @@
+What:		/sys/class/als/als[0-N]/desc
+Date:		Aug. 2009
+KernelVersion:	2.6.32
+Contact:	Zhang Rui <rui.zhang@intel.com>
+Description:	Strings which descibes the current Ambient Light Sensor
+		device. This is given by native ALS driver as part of
+		registration. e.g: "acpi_als" for ACPI ALS devices.
+		RO
+
+What:		/sys/class/als/als[0-N]/illuminance
+Date:		Aug. 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/als[0-N]/mapping[0-N]
+Date:		Aug. 2009
+KernelVersion:	2.6.32
+Contact:	Zhang Rui <rui.zhang@intel.com>
+Description:	represent one item of the Ambient Light Illuminance
+		to Display Luminance Adjustment mappings.
+
+What:		/sys/class/als/als[0-N]/mapping[0-N]/illuminance
+Date:		Aug. 2009
+KernelVersion:	2.6.32
+Contact:	Zhang Rui <rui.zhang@intel.com>
+Description:	ambient light illuminance threshold when a display
+		luminance(backlight) adjustment is needed.
+		RO
+
+What:		/sys/class/als/als[0-N]/mapping[0-N]/adjustment
+Date:		Aug. 2009
+KernelVersion:	2.6.32
+Contact:	Zhang Rui <rui.zhang@intel.com>
+Description:	a relative percentages in order simplify the means
+		by which these adjustments are applied in lieu of
+		changes to the user’s display brightness preference.
+		A value of 100 is used to indicate no (0%) display
+		brightness adjustment.
+		Values less than 100 indicate a negative adjustment
+		(dimming); values greater than 100 indicate a positive
+		adjustment (brightening).
+		RO
+



--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC] [PATCH v3 1/2] introduce ALS sysfs class
@ 2009-08-21  1:54     ` Zhang Rui
  0 siblings, 0 replies; 9+ messages in thread
From: Zhang Rui @ 2009-08-21  1:54 UTC (permalink / raw)
  To: Greg KH
  Cc: Linux Kernel Mailing List, linux-acpi, Bjorn Helgaas,
	Pavel Machek, Len Brown

On Thu, 2009-08-20 at 00:01 +0800, Greg KH wrote:
> On Wed, Aug 19, 2009 at 04:40:29PM +0800, Zhang Rui wrote:
> > --- /dev/null
> > +++ linux-2.6/Documentation/ABI/testing/sysfs-class-als
> > @@ -0,0 +1,137 @@
> > +Ambient Light Sensor Sysfs driver How To
> > +=========================
> 
> <snip>
> 
> While this is a nice document, it does not follow the standard that the
> files in Documentation/ABI/ should be in.  Can you please read
> Documentation/ABI/README and convert the file to follow that?
> 
sure. done
refreshed patch attached.

Introduce ALS sysfs class device.

ALS sysfs class device provides a standard sysfs interface
for Ambient Light Sensor devices.

please read Documentation/ABI/testing/sysfs-class-als for detailed sysfs
designs.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 Documentation/ABI/testing/sysfs-class-als |   47 +++++
 drivers/Kconfig                           |    2 
 drivers/Makefile                          |    1 
 drivers/als/Kconfig                       |   10 +
 drivers/als/Makefile                      |    5 
 drivers/als/als_sys.c                     |  256 ++++++++++++++++++++++++++++++
 include/linux/als_sys.h                   |   57 ++++++
 7 files changed, 378 insertions(+)

Index: linux-2.6/drivers/Kconfig
===================================================================
--- linux-2.6.orig/drivers/Kconfig
+++ linux-2.6/drivers/Kconfig
@@ -62,6 +62,8 @@ source "drivers/power/Kconfig"
 
 source "drivers/hwmon/Kconfig"
 
+source "drivers/als/Kconfig"
+
 source "drivers/thermal/Kconfig"
 
 source "drivers/watchdog/Kconfig"
Index: linux-2.6/drivers/Makefile
===================================================================
--- linux-2.6.orig/drivers/Makefile
+++ linux-2.6/drivers/Makefile
@@ -76,6 +76,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/
Index: linux-2.6/drivers/als/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/Kconfig
@@ -0,0 +1,10 @@
+#
+# Ambient Light Sensor sysfs device configuration
+#
+
+menuconfig ALS
+	tristate "Ambient Light Sensor sysfs device"
+	help
+	  This framework provides a generic sysfs interface for
+	  Ambient Light Sensor devices.
+	  If you want this support, you should say Y or M here.
Index: linux-2.6/drivers/als/Makefile
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for sensor chip drivers.
+#
+
+obj-$(CONFIG_ALS)		+= als_sys.o
Index: linux-2.6/drivers/als/als_sys.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/als/als_sys.c
@@ -0,0 +1,256 @@
+/*
+ *  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/als_sys.h>
+
+MODULE_AUTHOR("Zhang Rui");
+MODULE_DESCRIPTION("Ambient Light Sensor sysfs support");
+MODULE_LICENSE("GPL");
+
+struct als_mapping_item {
+	struct kobject kobj;
+	int index;
+	struct list_head node;
+};
+
+/* sys I/F for Ambient Light Sensor */
+
+#define to_als_device(dev) container_of(dev, struct als_device, device)
+
+static ssize_t
+desc_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct als_device *als = to_als_device(dev);
+
+	return sprintf(buf, "%s\n", als->desc ? als->desc : "N/A");
+}
+
+static ssize_t
+illuminance_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct als_device *als = to_als_device(dev);
+	int illuminance;
+	int result;
+
+	result = als->ops->get_illuminance(als, &illuminance);
+	if (result)
+		return result;
+
+	if (!illuminance)
+		return sprintf(buf, "Illuminance below the supported range\n");
+	else if (illuminance == -1)
+		return sprintf(buf, "Illuminance above the supported range\n");
+	else if (illuminance < -1)
+		return -ERANGE;
+	else
+		return sprintf(buf, "%d\n", illuminance);
+}
+
+static struct device_attribute als_attrs[] = {
+	__ATTR(desc, 0444, desc_show, NULL),
+	__ATTR(illuminance, 0444, illuminance_show, NULL),
+	__ATTR_NULL,
+};
+
+static void als_release(struct device *dev)
+{
+	struct als_device *als = to_als_device(dev);
+	struct als_mapping_item *pos, *n;
+
+	if (als->desc)
+		kfree(als->desc);
+	list_for_each_entry_safe(pos, n, &als->mappings, node){
+		list_del(&pos->node);
+		kfree(pos);
+	}
+	kfree(als);
+}
+
+static struct class als_class = {
+	.name = "als",
+	.dev_release = als_release,
+	.dev_attrs = als_attrs,
+};
+
+#define ATTR(_name, _mode)      \
+	struct attribute als_##_name##_attr = {               \
+	.name = __stringify(_name), .mode = _mode, \
+	};
+
+static ATTR(illuminance, 0444);
+static ATTR(adjustment, 0444);
+
+static struct attribute * als_mapping_attrs[] = {
+	&als_illuminance_attr,
+	&als_adjustment_attr,
+	NULL,
+};
+
+static ssize_t show_mapping_info(struct kobject *kobj,
+				       struct attribute *attr, char *buf)
+{
+	struct device *dev = container_of(kobj->parent, struct device, kobj);
+	struct als_device *als = to_als_device(dev);
+	int index, illuminance, adjustment;
+	int result;
+
+	if (!sscanf(kobj->name, "mapping%d", &index))
+		return -EINVAL;
+
+	result = als->ops->get_mapping_info(als, index, &illuminance, &adjustment);
+	if (result)
+		return result;
+
+	return sprintf(buf, "%u\n", (attr == &als_illuminance_attr) ? illuminance : adjustment);
+}
+
+static struct sysfs_ops als_mapping_info_ops = {
+	.show = show_mapping_info,
+	.store = NULL,
+};
+
+static struct kobj_type als_mapping_ktype = {
+	.sysfs_ops = &als_mapping_info_ops,
+	.default_attrs = als_mapping_attrs,
+};
+
+/**
+ * als_device_update_mappings - update the ambient light illuminance to
+ * 				display luminance adjustment mappings
+ */
+int als_device_update_mappings(struct als_device *als, int count)
+{
+	int old_count = als->count;
+	int i;
+	struct als_mapping_item *pos, *next;
+	int result;
+
+	als->count = count;
+	if (old_count == als->count)
+		return 0;
+
+	mutex_lock(&als->lock);
+	if (als->count > old_count)
+		for (i = old_count; i < als->count; i++) {
+			pos = kzalloc(sizeof(struct als_mapping_item), GFP_KERNEL);
+			if (!pos)
+				return -ENOMEM;
+
+			pos->index = i;
+			result = kobject_init_and_add(&pos->kobj, &als_mapping_ktype,
+					&als->device.kobj, "mapping%d", pos->index);
+			if (result)
+				break;
+			list_add_tail(&pos->node, &als->mappings);
+		}
+	else
+		list_for_each_entry_safe(pos, next, &als->mappings, node) {
+			if (pos->index < als->count)
+				continue;
+			list_del(&pos->node);
+			kobject_put(&pos->kobj);
+			kfree(pos);
+		}
+
+	if (result)
+		als->count = i;
+	mutex_unlock(&als->lock);
+	return 0;
+}
+
+EXPORT_SYMBOL(als_device_update_mappings);
+
+/**
+ * als_device_register - register a new Ambient Light Sensor class device
+ * @ops:	standard ALS devices callbacks.
+ * @devdata:	device private data.
+ */
+struct als_device *als_device_register(struct als_device_ops *ops,
+				       char *desc, void *devdata)
+{
+	struct als_device *als;
+	static int als_id;
+	int result;
+
+	if (!ops || !ops->get_illuminance)
+		return ERR_PTR(-EINVAL);
+
+	als = kzalloc(sizeof(struct als_device), GFP_KERNEL);
+	if (!als)
+		return ERR_PTR(-ENOMEM);
+
+	als->ops = ops;
+	als->device.class = &als_class;
+	als->devdata = devdata;
+	als->id = als_id++;
+	INIT_LIST_HEAD(&als->mappings);
+	mutex_init(&als->lock);
+	if (desc) {
+		als->desc = kzalloc(strlen(desc), GFP_KERNEL);
+		if (!als->desc) {
+			kfree(als);
+			return ERR_PTR(-ENOMEM);
+		}
+		strcpy(als->desc, desc);
+	}
+	dev_set_name(&als->device, "als%d", als->id);
+	result = device_register(&als->device);
+	if (result) {
+		if (als->desc)
+			kfree(als->desc);
+		kfree(als);
+		return ERR_PTR(result);
+	}
+
+	return als;
+}
+
+EXPORT_SYMBOL(als_device_register);
+
+/**
+ * als_device_unregister - removes the registered ALS device
+ * @als:	the ALS device to remove.
+ */
+void als_device_unregister(struct als_device *als)
+{
+	device_unregister(&als->device);
+}
+
+EXPORT_SYMBOL(als_device_unregister);
+
+static int __init als_init(void)
+{
+	return class_register(&als_class);
+}
+
+static void __exit als_exit(void)
+{
+	class_unregister(&als_class);
+}
+
+subsys_initcall(als_init);
+module_exit(als_exit);
Index: linux-2.6/include/linux/als_sys.h
===================================================================
--- /dev/null
+++ linux-2.6/include/linux/als_sys.h
@@ -0,0 +1,57 @@
+/*
+ *  als.h  ($Revision: 0 $)
+ *
+ *  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>
+
+struct als_device;
+
+struct als_device_ops {
+	int (*get_illuminance) (struct als_device *, int *);
+	int (*get_mapping_info) (struct als_device *, int, int *, int *);
+};
+
+struct als_mapping {
+	int illuminance;
+	int adjustment;
+};
+
+struct als_device {
+	int id;
+	int illuminance;
+	struct device device;
+	struct als_device_ops *ops;
+	void *devdata;
+	char *desc;
+	int count;
+	struct list_head mappings;
+	struct mutex lock;
+};
+
+int als_device_update_mappings(struct als_device *, int);
+struct als_device *als_device_register(struct als_device_ops *, char *, void *);
+void als_device_unregister(struct als_device *);
+
+#endif /* __ALS_SYS_H__ */
Index: linux-2.6/Documentation/ABI/testing/sysfs-class-als
===================================================================
--- /dev/null
+++ linux-2.6/Documentation/ABI/testing/sysfs-class-als
@@ -0,0 +1,47 @@
+What:		/sys/class/als/als[0-N]/desc
+Date:		Aug. 2009
+KernelVersion:	2.6.32
+Contact:	Zhang Rui <rui.zhang@intel.com>
+Description:	Strings which descibes the current Ambient Light Sensor
+		device. This is given by native ALS driver as part of
+		registration. e.g: "acpi_als" for ACPI ALS devices.
+		RO
+
+What:		/sys/class/als/als[0-N]/illuminance
+Date:		Aug. 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/als[0-N]/mapping[0-N]
+Date:		Aug. 2009
+KernelVersion:	2.6.32
+Contact:	Zhang Rui <rui.zhang@intel.com>
+Description:	represent one item of the Ambient Light Illuminance
+		to Display Luminance Adjustment mappings.
+
+What:		/sys/class/als/als[0-N]/mapping[0-N]/illuminance
+Date:		Aug. 2009
+KernelVersion:	2.6.32
+Contact:	Zhang Rui <rui.zhang@intel.com>
+Description:	ambient light illuminance threshold when a display
+		luminance(backlight) adjustment is needed.
+		RO
+
+What:		/sys/class/als/als[0-N]/mapping[0-N]/adjustment
+Date:		Aug. 2009
+KernelVersion:	2.6.32
+Contact:	Zhang Rui <rui.zhang@intel.com>
+Description:	a relative percentages in order simplify the means
+		by which these adjustments are applied in lieu of
+		changes to the user’s display brightness preference.
+		A value of 100 is used to indicate no (0%) display
+		brightness adjustment.
+		Values less than 100 indicate a negative adjustment
+		(dimming); values greater than 100 indicate a positive
+		adjustment (brightening).
+		RO
+




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC] [PATCH v3 1/2] introduce ALS sysfs class
  2009-08-21  1:54     ` Zhang Rui
  (?)
@ 2009-08-21 15:08     ` Greg KH
  2009-08-25  3:36       ` Zhang Rui
  -1 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2009-08-21 15:08 UTC (permalink / raw)
  To: Zhang Rui
  Cc: Linux Kernel Mailing List, linux-acpi, Bjorn Helgaas,
	Pavel Machek, Len Brown

On Fri, Aug 21, 2009 at 09:54:07AM +0800, Zhang Rui wrote:
> ---
>  Documentation/ABI/testing/sysfs-class-als |   47 +++++
>  drivers/Kconfig                           |    2 
>  drivers/Makefile                          |    1 
>  drivers/als/Kconfig                       |   10 +
>  drivers/als/Makefile                      |    5 
>  drivers/als/als_sys.c                     |  256 ++++++++++++++++++++++++++++++
>  include/linux/als_sys.h                   |   57 ++++++

Does this file really need to be in include/linux/ ?

Or could you just put it into drivers/als/ and it would be fine?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFC] [PATCH v3 1/2] introduce ALS sysfs class
  2009-08-21 15:08     ` Greg KH
@ 2009-08-25  3:36       ` Zhang Rui
  0 siblings, 0 replies; 9+ messages in thread
From: Zhang Rui @ 2009-08-25  3:36 UTC (permalink / raw)
  To: Greg KH
  Cc: Linux Kernel Mailing List, linux-acpi, Bjorn Helgaas,
	Pavel Machek, Len Brown

On Fri, 2009-08-21 at 23:08 +0800, Greg KH wrote:
> On Fri, Aug 21, 2009 at 09:54:07AM +0800, Zhang Rui wrote:
> > ---
> >  Documentation/ABI/testing/sysfs-class-als |   47 +++++
> >  drivers/Kconfig                           |    2 
> >  drivers/Makefile                          |    1 
> >  drivers/als/Kconfig                       |   10 +
> >  drivers/als/Makefile                      |    5 
> >  drivers/als/als_sys.c                     |  256 ++++++++++++++++++++++++++++++
> >  include/linux/als_sys.h                   |   57 ++++++
> 
> Does this file really need to be in include/linux/ ?
> 
> Or could you just put it into drivers/als/ and it would be fine?
> 
I don't think so, because all the other native ALS drivers like ACPI ALS
driver should depend on this header file.

thanks,
rui


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2009-08-25  3:38 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-19  8:40 [RFC] [PATCH v3 1/2] introduce ALS sysfs class Zhang Rui
2009-08-19  8:40 ` Zhang Rui
2009-08-19  8:57 ` Zhang Rui
2009-08-19  8:57   ` Zhang Rui
2009-08-19 16:01 ` Greg KH
2009-08-21  1:54   ` Zhang Rui
2009-08-21  1:54     ` Zhang Rui
2009-08-21 15:08     ` Greg KH
2009-08-25  3:36       ` Zhang Rui

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.