* [PATCH] ALS: TSL2550 driver move from i2c/chips
@ 2009-10-09 14:37 Jonathan Cameron
2009-10-09 15:05 ` Jonathan Cameron
[not found] ` <4ACF4AC6.7070802-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>
0 siblings, 2 replies; 14+ messages in thread
From: Jonathan Cameron @ 2009-10-09 14:37 UTC (permalink / raw)
To: LKML
Cc: Zhang Rui, Jean Delvare, Rodolfo Giometti, Michele De Candia (VT),
Linux I2C
Signed-off-by: Jonathan Cameron <jic23-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>
---
Minimal changes made. Untested due to lack of hardware.
All comments welcome.
illuminance is already documented as part of the class.
operating mode and power state are both as per the original
driver. I can't find any documentation for them, but if people
want it I can probably figure out what they are from
the data sheet.
Might be worth dropping the power state control and moving
over to runtime pm but that is definitely the topic for another
patch.
Does anyone want a patch without using Git's move functionality?
Have copied all the users Jean knows about, but please cc any other
users as this does involve a change to the userspace interface.
Applies on 2.6.31-rc3 with the ALS patches
http://patchwork.kernel.org/patch/49153/
drivers/als/Kconfig | 14 ++++++
drivers/als/Makefile | 2 +
drivers/{i2c/chips => als}/tsl2550.c | 73 ++++++++++++++++++++++++++++++---
3 files changed, 82 insertions(+), 7 deletions(-)
diff --git a/drivers/als/Kconfig b/drivers/als/Kconfig
index 200c52b..0c5dbb2 100644
--- a/drivers/als/Kconfig
+++ b/drivers/als/Kconfig
@@ -8,3 +8,17 @@ menuconfig ALS
This framework provides a generic sysfs I/F for Ambient Light
Sensor devices.
If you want this support, you should say Y or M here.
+
+if ALS
+
+config ALS_TSL2550
+ tristate "Taos TSL2550 ambient light sensor"
+ depends on EXPERIMENTAL
+ help
+ If you say yes here you get support for the Taos TSL2550
+ ambient light sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called tsl2550.
+
+endif #ALS
diff --git a/drivers/als/Makefile b/drivers/als/Makefile
index a527197..7be5631 100644
--- a/drivers/als/Makefile
+++ b/drivers/als/Makefile
@@ -3,3 +3,5 @@
#
obj-$(CONFIG_ALS) += als_sys.o
+
+obj-$(CONFIG_ALS_TSL2550) += tsl2550.o
\ No newline at end of file
diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/als/tsl2550.c
similarity index 87%
rename from drivers/i2c/chips/tsl2550.c
rename to drivers/als/tsl2550.c
index aa96bd2..6c11695 100644
--- a/drivers/i2c/chips/tsl2550.c
+++ b/drivers/als/tsl2550.c
@@ -24,9 +24,12 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/idr.h>
+#include <linux/als_sys.h>
#define TSL2550_DRV_NAME "tsl2550"
-#define DRIVER_VERSION "1.2"
+#define DRIVER_VERSION "2"
/*
* Defines
@@ -44,8 +47,10 @@
*/
struct tsl2550_data {
+ struct device *classdev;
struct i2c_client *client;
struct mutex update_lock;
+ unsigned int id;
unsigned int power_state : 1;
unsigned int operating_mode : 1;
@@ -60,9 +65,41 @@ static const u8 TSL2550_MODE_RANGE[2] = {
};
/*
+ * IDR to assign each registered device a unique id
+ */
+static DEFINE_IDR(tsl2550_idr);
+static DEFINE_SPINLOCK(tsl2550_idr_lock);
+#define TSL2550_DEV_MAX 9
+
+/*
* Management functions
*/
+static int tsl2550_get_id(void)
+{
+ int ret, val;
+
+idr_again:
+ if (unlikely(idr_pre_get(&tsl2550_idr, GFP_KERNEL) == 0))
+ return -ENOMEM;
+ spin_lock(&tsl2550_idr_lock);
+ ret = idr_get_new(&tsl2550_idr, NULL, &val);
+ if (unlikely(ret == -EAGAIN))
+ goto idr_again;
+ else if (unlikely(ret))
+ return ret;
+ if (val > TSL2550_DEV_MAX)
+ return -ENOMEM;
+ return val;
+}
+
+static void tsl2550_free_id(int val)
+{
+ spin_lock(&tsl2550_idr_lock);
+ idr_remove(&tsl2550_idr, val);
+ spin_unlock(&tsl2550_idr_lock);
+}
+
static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
{
struct tsl2550_data *data = i2c_get_clientdata(client);
@@ -296,13 +333,13 @@ static ssize_t tsl2550_show_lux1_input(struct device *dev,
return ret;
}
-static DEVICE_ATTR(lux1_input, S_IRUGO,
+static DEVICE_ATTR(illuminance, S_IRUGO,
tsl2550_show_lux1_input, NULL);
static struct attribute *tsl2550_attributes[] = {
&dev_attr_power_state.attr,
&dev_attr_operating_mode.attr,
- &dev_attr_lux1_input.attr,
+ &dev_attr_illuminance.attr,
NULL
};
@@ -350,6 +387,7 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct tsl2550_data *data;
int *opmode, err = 0;
+ char name[9];
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
| I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
@@ -387,15 +425,31 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
if (err)
goto exit_kfree;
+ data->id = tsl2550_get_id();
+ if (data->id < 0) {
+ err = data->id;
+ goto exit_kfree;
+ }
+ sprintf(name, "tsl2550%d", data->id);
/* Register sysfs hooks */
- err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
+ data->classdev = als_device_register(&client->dev, name);
+ if (IS_ERR(data->classdev)) {
+ err = PTR_ERR(data->classdev);
+ goto exit_free_id;
+ }
+
+ err = sysfs_create_group(&data->classdev->kobj, &tsl2550_attr_group);
if (err)
- goto exit_kfree;
+ goto exit_unreg;
dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
return 0;
+exit_unreg:
+ als_device_unregister(data->classdev);
+exit_free_id:
+ tsl2550_free_id(data->id);
exit_kfree:
kfree(data);
exit:
@@ -404,12 +458,17 @@ exit:
static int __devexit tsl2550_remove(struct i2c_client *client)
{
- sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
+ struct tsl2550_data *data = i2c_get_clientdata(client);
+
+ sysfs_remove_group(&data->classdev->kobj, &tsl2550_attr_group);
+ als_device_unregister(data->classdev);
/* Power down the device */
tsl2550_set_power_state(client, 0);
- kfree(i2c_get_clientdata(client));
+ tsl2550_free_id(data->id);
+
+ kfree(data);
return 0;
}
--
1.6.3.3
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [PATCH] ALS: TSL2550 driver move from i2c/chips
2009-10-09 14:37 [PATCH] ALS: TSL2550 driver move from i2c/chips Jonathan Cameron
@ 2009-10-09 15:05 ` Jonathan Cameron
[not found] ` <4ACF4AC6.7070802-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>
1 sibling, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2009-10-09 15:05 UTC (permalink / raw)
To: Jonathan Cameron
Cc: LKML, Zhang Rui, Jean Delvare, Rodolfo Giometti,
Michele De Candia (VT), Linux I2C
Gah, I forgot the I2C dependency as well.
Sorry for the silly errors.
> Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
>
> ---
> Minimal changes made. Untested due to lack of hardware.
> All comments welcome.
>
> illuminance is already documented as part of the class.
> operating mode and power state are both as per the original
> driver. I can't find any documentation for them, but if people
> want it I can probably figure out what they are from
> the data sheet.
>
> Might be worth dropping the power state control and moving
> over to runtime pm but that is definitely the topic for another
> patch.
>
> Does anyone want a patch without using Git's move functionality?
>
> Have copied all the users Jean knows about, but please cc any other
> users as this does involve a change to the userspace interface.
>
> Applies on 2.6.31-rc3 with the ALS patches
> http://patchwork.kernel.org/patch/49153/
>
> drivers/als/Kconfig | 14 ++++++
> drivers/als/Makefile | 2 +
> drivers/{i2c/chips => als}/tsl2550.c | 73 ++++++++++++++++++++++++++++++---
> 3 files changed, 82 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/als/Kconfig b/drivers/als/Kconfig
> index 200c52b..0c5dbb2 100644
> --- a/drivers/als/Kconfig
> +++ b/drivers/als/Kconfig
> @@ -8,3 +8,17 @@ menuconfig ALS
> This framework provides a generic sysfs I/F for Ambient Light
> Sensor devices.
> If you want this support, you should say Y or M here.
> +
> +if ALS
> +
> +config ALS_TSL2550
> + tristate "Taos TSL2550 ambient light sensor"
> + depends on EXPERIMENTAL
> + help
> + If you say yes here you get support for the Taos TSL2550
> + ambient light sensor.
> +
> + This driver can also be built as a module. If so, the module
> + will be called tsl2550.
> +
> +endif #ALS
> diff --git a/drivers/als/Makefile b/drivers/als/Makefile
> index a527197..7be5631 100644
> --- a/drivers/als/Makefile
> +++ b/drivers/als/Makefile
> @@ -3,3 +3,5 @@
> #
>
> obj-$(CONFIG_ALS) += als_sys.o
> +
> +obj-$(CONFIG_ALS_TSL2550) += tsl2550.o
> \ No newline at end of file
> diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/als/tsl2550.c
> similarity index 87%
> rename from drivers/i2c/chips/tsl2550.c
> rename to drivers/als/tsl2550.c
> index aa96bd2..6c11695 100644
> --- a/drivers/i2c/chips/tsl2550.c
> +++ b/drivers/als/tsl2550.c
> @@ -24,9 +24,12 @@
> #include <linux/slab.h>
> #include <linux/i2c.h>
> #include <linux/mutex.h>
> +#include <linux/err.h>
> +#include <linux/idr.h>
> +#include <linux/als_sys.h>
>
> #define TSL2550_DRV_NAME "tsl2550"
> -#define DRIVER_VERSION "1.2"
> +#define DRIVER_VERSION "2"
>
> /*
> * Defines
> @@ -44,8 +47,10 @@
> */
>
> struct tsl2550_data {
> + struct device *classdev;
> struct i2c_client *client;
> struct mutex update_lock;
> + unsigned int id;
>
> unsigned int power_state : 1;
> unsigned int operating_mode : 1;
> @@ -60,9 +65,41 @@ static const u8 TSL2550_MODE_RANGE[2] = {
> };
>
> /*
> + * IDR to assign each registered device a unique id
> + */
> +static DEFINE_IDR(tsl2550_idr);
> +static DEFINE_SPINLOCK(tsl2550_idr_lock);
> +#define TSL2550_DEV_MAX 9
> +
> +/*
> * Management functions
> */
>
> +static int tsl2550_get_id(void)
> +{
> + int ret, val;
> +
> +idr_again:
> + if (unlikely(idr_pre_get(&tsl2550_idr, GFP_KERNEL) == 0))
> + return -ENOMEM;
> + spin_lock(&tsl2550_idr_lock);
> + ret = idr_get_new(&tsl2550_idr, NULL, &val);
> + if (unlikely(ret == -EAGAIN))
> + goto idr_again;
> + else if (unlikely(ret))
> + return ret;
> + if (val > TSL2550_DEV_MAX)
> + return -ENOMEM;
> + return val;
> +}
> +
> +static void tsl2550_free_id(int val)
> +{
> + spin_lock(&tsl2550_idr_lock);
> + idr_remove(&tsl2550_idr, val);
> + spin_unlock(&tsl2550_idr_lock);
> +}
> +
> static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
> {
> struct tsl2550_data *data = i2c_get_clientdata(client);
> @@ -296,13 +333,13 @@ static ssize_t tsl2550_show_lux1_input(struct device *dev,
> return ret;
> }
>
> -static DEVICE_ATTR(lux1_input, S_IRUGO,
> +static DEVICE_ATTR(illuminance, S_IRUGO,
> tsl2550_show_lux1_input, NULL);
>
> static struct attribute *tsl2550_attributes[] = {
> &dev_attr_power_state.attr,
> &dev_attr_operating_mode.attr,
> - &dev_attr_lux1_input.attr,
> + &dev_attr_illuminance.attr,
> NULL
> };
>
> @@ -350,6 +387,7 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
> struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
> struct tsl2550_data *data;
> int *opmode, err = 0;
> + char name[9];
>
> if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
> | I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
> @@ -387,15 +425,31 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
> if (err)
> goto exit_kfree;
>
> + data->id = tsl2550_get_id();
> + if (data->id < 0) {
> + err = data->id;
> + goto exit_kfree;
> + }
> + sprintf(name, "tsl2550%d", data->id);
> /* Register sysfs hooks */
> - err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
> + data->classdev = als_device_register(&client->dev, name);
> + if (IS_ERR(data->classdev)) {
> + err = PTR_ERR(data->classdev);
> + goto exit_free_id;
> + }
> +
> + err = sysfs_create_group(&data->classdev->kobj, &tsl2550_attr_group);
> if (err)
> - goto exit_kfree;
> + goto exit_unreg;
>
> dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
>
> return 0;
>
> +exit_unreg:
> + als_device_unregister(data->classdev);
> +exit_free_id:
> + tsl2550_free_id(data->id);
> exit_kfree:
> kfree(data);
> exit:
> @@ -404,12 +458,17 @@ exit:
>
> static int __devexit tsl2550_remove(struct i2c_client *client)
> {
> - sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
> + struct tsl2550_data *data = i2c_get_clientdata(client);
> +
> + sysfs_remove_group(&data->classdev->kobj, &tsl2550_attr_group);
> + als_device_unregister(data->classdev);
>
> /* Power down the device */
> tsl2550_set_power_state(client, 0);
>
> - kfree(i2c_get_clientdata(client));
> + tsl2550_free_id(data->id);
> +
> + kfree(data);
>
> return 0;
> }
^ permalink raw reply [flat|nested] 14+ messages in thread[parent not found: <4ACF4AC6.7070802-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>]
* Re: [PATCH] ALS: TSL2550 driver move from i2c/chips
[not found] ` <4ACF4AC6.7070802-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>
@ 2009-10-09 14:53 ` Jonathan Cameron
2009-10-10 16:33 ` Jean Delvare
2009-10-10 16:52 ` Jean Delvare
2 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2009-10-09 14:53 UTC (permalink / raw)
To: Jonathan Cameron
Cc: LKML, Zhang Rui, Jean Delvare, Rodolfo Giometti,
Michele De Candia (VT), Linux I2C
Friday afternoon moment....
That id element will need to be signed for any errors on idr allocation
to be detected. Will fix for next version.
> struct tsl2550_data {
> + struct device *classdev;
> struct i2c_client *client;
> struct mutex update_lock;
> + unsigned int id;
>
> unsigned int power_state : 1;
> unsigned int operating_mode : 1;
>
....
>
> + data->id = tsl2550_get_id();
> + if (data->id < 0) {
> + err = data->id;
> + goto exit_kfree;
> + }
>
Jonathan
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH] ALS: TSL2550 driver move from i2c/chips
[not found] ` <4ACF4AC6.7070802-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>
2009-10-09 14:53 ` Jonathan Cameron
@ 2009-10-10 16:33 ` Jean Delvare
[not found] ` <20091010183347.52b043ed-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-10-10 16:52 ` Jean Delvare
2 siblings, 1 reply; 14+ messages in thread
From: Jean Delvare @ 2009-10-10 16:33 UTC (permalink / raw)
To: Jonathan Cameron
Cc: LKML, Zhang Rui, Rodolfo Giometti, Michele De Candia (VT),
Linux I2C
Hi Jonathan,
On Fri, 09 Oct 2009 15:37:58 +0100, Jonathan Cameron wrote:
>
> Signed-off-by: Jonathan Cameron <jic23-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>
>
> ---
> Minimal changes made. Untested due to lack of hardware.
> All comments welcome.
Thanks for working on this. I can do any amount of testing you want, as
I have received a TSL2550 evaluation module from TAOS.
> illuminance is already documented as part of the class.
> operating mode and power state are both as per the original
> driver. I can't find any documentation for them, but if people
> want it I can probably figure out what they are from
> the data sheet.
The operating mode selects the measurable range. Standard range is from
0 to 1846 lux, extended range is from 0 to 9230 lux, with a resolution
divided by 5. Extended mode is also 5 times faster.
What do we want to do with this? I am open to suggestions. There are
several possibilities. The operating mode could be provided as platform
data and stay internal to the driver. Or we can leave is visible to
user-space, in which case I'd recommend that we do so in terms of
"range" rather than "mode", so that other drivers can use the same
convention, whatever it becomes. For example, one would write the range
of values he/she wants to be able to measure and the driver would put
the device in the most appropriate mode.
Alternatively (or additionally), we could implement an automatic mode
which would change the mode dynamically based on the previous
measurement. I've done that for one hwmon driver (for fan speed
measurement) and it works very well, if implemented properly.
> Might be worth dropping the power state control and moving
> over to runtime pm but that is definitely the topic for another
> patch.
Power state control is already integrated into the PM framework
(suspend and resume, is there more?) The sysfs entry is to allow a
manual control on top of it. I don't much like having a custom sysfs
entry for this, but I don't know if there is a standard way to achieve
the same?
> Does anyone want a patch without using Git's move functionality?
Yes please!
> Have copied all the users Jean knows about, but please cc any other
> users as this does involve a change to the userspace interface.
>
> Applies on 2.6.31-rc3 with the ALS patches
> http://patchwork.kernel.org/patch/49153/
>
> drivers/als/Kconfig | 14 ++++++
> drivers/als/Makefile | 2 +
> drivers/{i2c/chips => als}/tsl2550.c | 73 ++++++++++++++++++++++++++++++---
> 3 files changed, 82 insertions(+), 7 deletions(-)
--
Jean Delvare
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH] ALS: TSL2550 driver move from i2c/chips
[not found] ` <4ACF4AC6.7070802-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>
2009-10-09 14:53 ` Jonathan Cameron
2009-10-10 16:33 ` Jean Delvare
@ 2009-10-10 16:52 ` Jean Delvare
2009-10-12 14:19 ` Jonathan Cameron
2 siblings, 1 reply; 14+ messages in thread
From: Jean Delvare @ 2009-10-10 16:52 UTC (permalink / raw)
To: Jonathan Cameron
Cc: LKML, Zhang Rui, Rodolfo Giometti, Michele De Candia (VT),
Linux I2C
On Fri, 09 Oct 2009 15:37:58 +0100, Jonathan Cameron wrote:
> drivers/als/Kconfig | 14 ++++++
> drivers/als/Makefile | 2 +
> drivers/{i2c/chips => als}/tsl2550.c | 73 ++++++++++++++++++++++++++++++---
> 3 files changed, 82 insertions(+), 7 deletions(-)
Review:
> diff --git a/drivers/als/Kconfig b/drivers/als/Kconfig
> index 200c52b..0c5dbb2 100644
> --- a/drivers/als/Kconfig
> +++ b/drivers/als/Kconfig
> @@ -8,3 +8,17 @@ menuconfig ALS
> This framework provides a generic sysfs I/F for Ambient Light
> Sensor devices.
> If you want this support, you should say Y or M here.
> +
> +if ALS
> +
> +config ALS_TSL2550
> + tristate "Taos TSL2550 ambient light sensor"
> + depends on EXPERIMENTAL
As you found out already, you need to depend on I2C as well.
> + help
> + If you say yes here you get support for the Taos TSL2550
> + ambient light sensor.
> +
> + This driver can also be built as a module. If so, the module
> + will be called tsl2550.
> +
> +endif #ALS
> diff --git a/drivers/als/Makefile b/drivers/als/Makefile
> index a527197..7be5631 100644
> --- a/drivers/als/Makefile
> +++ b/drivers/als/Makefile
> @@ -3,3 +3,5 @@
> #
>
> obj-$(CONFIG_ALS) += als_sys.o
> +
> +obj-$(CONFIG_ALS_TSL2550) += tsl2550.o
> \ No newline at end of file
> diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/als/tsl2550.c
> similarity index 87%
> rename from drivers/i2c/chips/tsl2550.c
> rename to drivers/als/tsl2550.c
> index aa96bd2..6c11695 100644
> --- a/drivers/i2c/chips/tsl2550.c
> +++ b/drivers/als/tsl2550.c
> @@ -24,9 +24,12 @@
> #include <linux/slab.h>
> #include <linux/i2c.h>
> #include <linux/mutex.h>
> +#include <linux/err.h>
> +#include <linux/idr.h>
> +#include <linux/als_sys.h>
>
> #define TSL2550_DRV_NAME "tsl2550"
> -#define DRIVER_VERSION "1.2"
> +#define DRIVER_VERSION "2"
"2.0"?
>
> /*
> * Defines
> @@ -44,8 +47,10 @@
> */
>
> struct tsl2550_data {
> + struct device *classdev;
> struct i2c_client *client;
> struct mutex update_lock;
> + unsigned int id;
>
> unsigned int power_state : 1;
> unsigned int operating_mode : 1;
> @@ -60,9 +65,41 @@ static const u8 TSL2550_MODE_RANGE[2] = {
> };
>
> /*
> + * IDR to assign each registered device a unique id
> + */
> +static DEFINE_IDR(tsl2550_idr);
> +static DEFINE_SPINLOCK(tsl2550_idr_lock);
> +#define TSL2550_DEV_MAX 9
Such an arbitrary limit is simply not acceptable.
> +
> +/*
> * Management functions
> */
>
> +static int tsl2550_get_id(void)
> +{
> + int ret, val;
> +
> +idr_again:
> + if (unlikely(idr_pre_get(&tsl2550_idr, GFP_KERNEL) == 0))
> + return -ENOMEM;
> + spin_lock(&tsl2550_idr_lock);
> + ret = idr_get_new(&tsl2550_idr, NULL, &val);
> + if (unlikely(ret == -EAGAIN))
> + goto idr_again;
> + else if (unlikely(ret))
> + return ret;
> + if (val > TSL2550_DEV_MAX)
> + return -ENOMEM;
> + return val;
> +}
> +
> +static void tsl2550_free_id(int val)
> +{
> + spin_lock(&tsl2550_idr_lock);
> + idr_remove(&tsl2550_idr, val);
> + spin_unlock(&tsl2550_idr_lock);
> +}
Having to implement this in _every_ ALS driver sounds wrong and
painful. If uniqueness of any kind must be provided, it should be
handled by the ALS core and not by individual drivers, otherwise you
can be certain that at least one driver will get it wrong someday.
I'd imaging that als-class devices are simply named als%u. Just like
hwmon devices are named hwmon%u, input devices are names input%u and
event%u, etc. I don't know of any class pushing the naming down to its
drivers, do you? The only example I can remember are i2c drivers back
in year 1999, when they were part of lm-sensors.I have personally put
an end to this years ago.
> +
> static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
> {
> struct tsl2550_data *data = i2c_get_clientdata(client);
> @@ -296,13 +333,13 @@ static ssize_t tsl2550_show_lux1_input(struct device *dev,
> return ret;
> }
>
> -static DEVICE_ATTR(lux1_input, S_IRUGO,
> +static DEVICE_ATTR(illuminance, S_IRUGO,
> tsl2550_show_lux1_input, NULL);
Question: if I have a light sensing chip with two sensors, how are we
going to handle it? Will we register 2 als class devices? The initial
naming convention had the advantage that you could have more than one
sensor per device, but I don't know if it is desirable in practice.
>
> static struct attribute *tsl2550_attributes[] = {
> &dev_attr_power_state.attr,
> &dev_attr_operating_mode.attr,
> - &dev_attr_lux1_input.attr,
> + &dev_attr_illuminance.attr,
> NULL
> };
>
> @@ -350,6 +387,7 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
> struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
> struct tsl2550_data *data;
> int *opmode, err = 0;
> + char name[9];
>
> if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
> | I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
> @@ -387,15 +425,31 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
> if (err)
> goto exit_kfree;
>
> + data->id = tsl2550_get_id();
> + if (data->id < 0) {
> + err = data->id;
> + goto exit_kfree;
> + }
> + sprintf(name, "tsl2550%d", data->id);
Please no. For one thing you should always use snprintf and not sprintf
when writing to such small buffers. It's way too easy to get things
wrong otherwise. And you really want a separator between the chip name
and the id, because "tsl25500" will be confusing as hell.
Not that these comments of mine really matter, as I don't think the
above code should stay at all.
> /* Register sysfs hooks */
> - err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
> + data->classdev = als_device_register(&client->dev, name);
> + if (IS_ERR(data->classdev)) {
> + err = PTR_ERR(data->classdev);
> + goto exit_free_id;
> + }
> +
> + err = sysfs_create_group(&data->classdev->kobj, &tsl2550_attr_group);
> if (err)
> - goto exit_kfree;
> + goto exit_unreg;
>
> dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
>
> return 0;
>
> +exit_unreg:
> + als_device_unregister(data->classdev);
> +exit_free_id:
> + tsl2550_free_id(data->id);
> exit_kfree:
> kfree(data);
> exit:
> @@ -404,12 +458,17 @@ exit:
>
> static int __devexit tsl2550_remove(struct i2c_client *client)
> {
> - sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
> + struct tsl2550_data *data = i2c_get_clientdata(client);
> +
> + sysfs_remove_group(&data->classdev->kobj, &tsl2550_attr_group);
> + als_device_unregister(data->classdev);
>
> /* Power down the device */
> tsl2550_set_power_state(client, 0);
>
> - kfree(i2c_get_clientdata(client));
> + tsl2550_free_id(data->id);
> +
> + kfree(data);
>
> return 0;
> }
--
Jean Delvare
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH] ALS: TSL2550 driver move from i2c/chips
2009-10-10 16:52 ` Jean Delvare
@ 2009-10-12 14:19 ` Jonathan Cameron
2009-10-12 15:52 ` Jean Delvare
0 siblings, 1 reply; 14+ messages in thread
From: Jonathan Cameron @ 2009-10-12 14:19 UTC (permalink / raw)
To: Jean Delvare
Cc: LKML, Zhang Rui, Rodolfo Giometti, Michele De Candia (VT),
Linux I2C
For those not following this driver, Jean does raise the issue
of device naming again and I think we really need to settle
this one before progressing with ALS in general.
>
> "2.0"?
True, that would be consistent.
>
>>
>> /*
>> * Defines
>> @@ -44,8 +47,10 @@
>> */
>>
>> struct tsl2550_data {
>> + struct device *classdev;
>> struct i2c_client *client;
>> struct mutex update_lock;
>> + unsigned int id;
>>
>> unsigned int power_state : 1;
>> unsigned int operating_mode : 1;
>> @@ -60,9 +65,41 @@ static const u8 TSL2550_MODE_RANGE[2] = {
>> };
>>
>> /*
>> + * IDR to assign each registered device a unique id
>> + */
>> +static DEFINE_IDR(tsl2550_idr);
>> +static DEFINE_SPINLOCK(tsl2550_idr_lock);
>> +#define TSL2550_DEV_MAX 9
>
> Such an arbitrary limit is simply not acceptable.
Fair enough, but it is based on restricting the size
of the char array needed for the name when registering
with als. Hence single digit decimal maximum.
Do you suggest leaving it unrestricted (which makes code
a little fiddly given variable size of max idr) or some other
limit?
>> +
>> +/*
>> * Management functions
>> */
>>
>> +static int tsl2550_get_id(void)
>> +{
>> + int ret, val;
>> +
>> +idr_again:
>> + if (unlikely(idr_pre_get(&tsl2550_idr, GFP_KERNEL) == 0))
>> + return -ENOMEM;
>> + spin_lock(&tsl2550_idr_lock);
>> + ret = idr_get_new(&tsl2550_idr, NULL, &val);
>> + if (unlikely(ret == -EAGAIN))
>> + goto idr_again;
>> + else if (unlikely(ret))
>> + return ret;
>> + if (val > TSL2550_DEV_MAX)
>> + return -ENOMEM;
>> + return val;
>> +}
>> +
>> +static void tsl2550_free_id(int val)
>> +{
>> + spin_lock(&tsl2550_idr_lock);
>> + idr_remove(&tsl2550_idr, val);
>> + spin_unlock(&tsl2550_idr_lock);
>> +}
>
> Having to implement this in _every_ ALS driver sounds wrong and
> painful. If uniqueness of any kind must be provided, it should be
> handled by the ALS core and not by individual drivers, otherwise you
> can be certain that at least one driver will get it wrong someday.
I agree. The reason this originally occurred is that the acpi layer
apparently doesn't allow for simultaneous probing of multiple drivers
and hence can get away with a simple counter and no locking.
>
> I'd imaging that als-class devices are simply named als%u. Just like
> hwmon devices are named hwmon%u, input devices are names input%u and
> event%u, etc. I don't know of any class pushing the naming down to its
> drivers, do you? The only example I can remember are i2c drivers back
> in year 1999, when they were part of lm-sensors.I have personally put
> an end to this years ago.
This debate started in the als thread. Personally I couldn't care less
either way but it does need to be put to bed before that subsystem merges.
To my mind either approach is trivially handled in a userspace library
so it doesn't matter. I don't suppose you can remember what the original
reasons for squashing this naming approach were?
>
>> +
>> static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
>> {
>> struct tsl2550_data *data = i2c_get_clientdata(client);
>> @@ -296,13 +333,13 @@ static ssize_t tsl2550_show_lux1_input(struct device *dev,
>> return ret;
>> }
>>
>> -static DEVICE_ATTR(lux1_input, S_IRUGO,
>> +static DEVICE_ATTR(illuminance, S_IRUGO,
>> tsl2550_show_lux1_input, NULL);
>
> Question: if I have a light sensing chip with two sensors, how are we
> going to handle it? Will we register 2 als class devices? The initial
> naming convention had the advantage that you could have more than one
> sensor per device, but I don't know if it is desirable in practice.
This only becomes and issue if we have two sensors measuring illuminance
(or approximation of it). The only two sensor chips I know of have one
broadband and one in the infrared tsl2561 and I think the isl chip with
a driver currently in misc. The combination of these two are needed to
calculate illuminance. Some of the original discussion went into how
to support separate access to the individual sensors. Decision was to
leave that question until it becomes relevant. Basically we would put
the current drivers in just supporting illuminance and see if anyone asked
for furthers support. One tricky aspect is what the units should be for
particular frequency ranges. At least illuminance is cleanly defined
(even if chips are only fairly coarsely approximating it.
>
>>
>> static struct attribute *tsl2550_attributes[] = {
>> &dev_attr_power_state.attr,
>> &dev_attr_operating_mode.attr,
>> - &dev_attr_lux1_input.attr,
>> + &dev_attr_illuminance.attr,
>> NULL
>> };
>>
>> @@ -350,6 +387,7 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
>> struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
>> struct tsl2550_data *data;
>> int *opmode, err = 0;
>> + char name[9];
>>
>> if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
>> | I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
>> @@ -387,15 +425,31 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
>> if (err)
>> goto exit_kfree;
>>
>> + data->id = tsl2550_get_id();
>> + if (data->id < 0) {
>> + err = data->id;
>> + goto exit_kfree;
>> + }
>> + sprintf(name, "tsl2550%d", data->id);
>
> Please no. For one thing you should always use snprintf and not sprintf
> when writing to such small buffers. It's way too easy to get things
> wrong otherwise. And you really want a separator between the chip name
> and the id, because "tsl25500" will be confusing as hell.
The length is fine with the restriction above, but I agree we need a separation
(hadn't really thought this through!).
>
> Not that these comments of mine really matter, as I don't think the
> above code should stay at all.
That's fair enough and I'm inclined to agree.
>
>> /* Register sysfs hooks */
>> - err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
>> + data->classdev = als_device_register(&client->dev, name);
>> + if (IS_ERR(data->classdev)) {
>> + err = PTR_ERR(data->classdev);
>> + goto exit_free_id;
>> + }
>> +
>> + err = sysfs_create_group(&data->classdev->kobj, &tsl2550_attr_group);
>> if (err)
>> - goto exit_kfree;
>> + goto exit_unreg;
>>
>> dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
>>
>> return 0;
>>
>> +exit_unreg:
>> + als_device_unregister(data->classdev);
>> +exit_free_id:
>> + tsl2550_free_id(data->id);
>> exit_kfree:
>> kfree(data);
>> exit:
>> @@ -404,12 +458,17 @@ exit:
>>
>> static int __devexit tsl2550_remove(struct i2c_client *client)
>> {
>> - sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
>> + struct tsl2550_data *data = i2c_get_clientdata(client);
>> +
>> + sysfs_remove_group(&data->classdev->kobj, &tsl2550_attr_group);
>> + als_device_unregister(data->classdev);
>>
>> /* Power down the device */
>> tsl2550_set_power_state(client, 0);
>>
>> - kfree(i2c_get_clientdata(client));
>> + tsl2550_free_id(data->id);
>> +
>> + kfree(data);
>>
>> return 0;
>> }
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH] ALS: TSL2550 driver move from i2c/chips
2009-10-12 14:19 ` Jonathan Cameron
@ 2009-10-12 15:52 ` Jean Delvare
[not found] ` <20091012175216.6d844623-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
0 siblings, 1 reply; 14+ messages in thread
From: Jean Delvare @ 2009-10-12 15:52 UTC (permalink / raw)
To: Jonathan Cameron
Cc: LKML, Zhang Rui, Rodolfo Giometti, Michele De Candia (VT),
Linux I2C
Hi Jonathan,
On Mon, 12 Oct 2009 15:19:07 +0100, Jonathan Cameron wrote:
> >> @@ -60,9 +65,41 @@ static const u8 TSL2550_MODE_RANGE[2] = {
> >> };
> >>
> >> /*
> >> + * IDR to assign each registered device a unique id
> >> + */
> >> +static DEFINE_IDR(tsl2550_idr);
> >> +static DEFINE_SPINLOCK(tsl2550_idr_lock);
> >> +#define TSL2550_DEV_MAX 9
> >
> > Such an arbitrary limit is simply not acceptable.
>
> Fair enough, but it is based on restricting the size
> of the char array needed for the name when registering
> with als. Hence single digit decimal maximum.
> Do you suggest leaving it unrestricted (which makes code
> a little fiddly given variable size of max idr) or some other
> limit?
The name size really isn't an issue. You won't notice 16 bytes instead
of 9. And it's not like we'll have millions of these devices.
> >> +static int tsl2550_get_id(void)
> >> +{
> >> + int ret, val;
> >> +
> >> +idr_again:
> >> + if (unlikely(idr_pre_get(&tsl2550_idr, GFP_KERNEL) == 0))
> >> + return -ENOMEM;
> >> + spin_lock(&tsl2550_idr_lock);
> >> + ret = idr_get_new(&tsl2550_idr, NULL, &val);
> >> + if (unlikely(ret == -EAGAIN))
> >> + goto idr_again;
> >> + else if (unlikely(ret))
> >> + return ret;
> >> + if (val > TSL2550_DEV_MAX)
> >> + return -ENOMEM;
> >> + return val;
> >> +}
> >> +
> >> +static void tsl2550_free_id(int val)
> >> +{
> >> + spin_lock(&tsl2550_idr_lock);
> >> + idr_remove(&tsl2550_idr, val);
> >> + spin_unlock(&tsl2550_idr_lock);
> >> +}
> >
> > Having to implement this in _every_ ALS driver sounds wrong and
> > painful. If uniqueness of any kind must be provided, it should be
> > handled by the ALS core and not by individual drivers, otherwise you
> > can be certain that at least one driver will get it wrong someday.
>
> I agree. The reason this originally occurred is that the acpi layer
> apparently doesn't allow for simultaneous probing of multiple drivers
> and hence can get away with a simple counter and no locking.
>
> > I'd imaging that als-class devices are simply named als%u. Just like
> > hwmon devices are named hwmon%u, input devices are names input%u and
> > event%u, etc. I don't know of any class pushing the naming down to its
> > drivers, do you? The only example I can remember are i2c drivers back
> > in year 1999, when they were part of lm-sensors.I have personally put
> > an end to this years ago.
>
> This debate started in the als thread. Personally I couldn't care less
> either way but it does need to be put to bed before that subsystem merges.
> To my mind either approach is trivially handled in a userspace library
> so it doesn't matter. I don't suppose you can remember what the original
> reasons for squashing this naming approach were?
Code duplication. Having the same unique-id handling code repeated in
50 drivers was no fun, as it did not add any value compared to a
central handling.
> >> @@ -296,13 +333,13 @@ static ssize_t tsl2550_show_lux1_input(struct device *dev,
> >> return ret;
> >> }
> >>
> >> -static DEVICE_ATTR(lux1_input, S_IRUGO,
> >> +static DEVICE_ATTR(illuminance, S_IRUGO,
> >> tsl2550_show_lux1_input, NULL);
> >
> > Question: if I have a light sensing chip with two sensors, how are we
> > going to handle it? Will we register 2 als class devices? The initial
> > naming convention had the advantage that you could have more than one
> > sensor per device, but I don't know if it is desirable in practice.
>
> This only becomes and issue if we have two sensors measuring illuminance
> (or approximation of it). The only two sensor chips I know of have one
> broadband and one in the infrared tsl2561 and I think the isl chip with
> a driver currently in misc. The combination of these two are needed to
> calculate illuminance. Some of the original discussion went into how
> to support separate access to the individual sensors. Decision was to
> leave that question until it becomes relevant. Basically we would put
> the current drivers in just supporting illuminance and see if anyone asked
> for furthers support. One tricky aspect is what the units should be for
> particular frequency ranges. At least illuminance is cleanly defined
> (even if chips are only fairly coarsely approximating it.
Hmm, this isn't the point I was raising. I was thinking of a light
sensor chip which would sense light in different locations. Think chip
with remote sensors. This is done frequently for thermal sensors, so I
guess it could be done for light sensors as well. A practical
application could be sensing the ambient light on two sides of an
object, so that you get the correct measurement regardless of the
position.
I'm not saying such chips exist, I really don't know. I am just raising
the question of how we'd handle them if they do. The current naming
scheme implies that we'd need a separate als instance for each sensor,
and I want you to be aware of this.
> >> static struct attribute *tsl2550_attributes[] = {
> >> &dev_attr_power_state.attr,
> >> &dev_attr_operating_mode.attr,
> >> - &dev_attr_lux1_input.attr,
> >> + &dev_attr_illuminance.attr,
> >> NULL
> >> };
> >>
> >> @@ -350,6 +387,7 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
> >> struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
> >> struct tsl2550_data *data;
> >> int *opmode, err = 0;
> >> + char name[9];
> >>
> >> if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
> >> | I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
> >> @@ -387,15 +425,31 @@ static int __devinit tsl2550_probe(struct i2c_client *client,
> >> if (err)
> >> goto exit_kfree;
> >>
> >> + data->id = tsl2550_get_id();
> >> + if (data->id < 0) {
> >> + err = data->id;
> >> + goto exit_kfree;
> >> + }
> >> + sprintf(name, "tsl2550%d", data->id);
> >
> > Please no. For one thing you should always use snprintf and not sprintf
> > when writing to such small buffers. It's way too easy to get things
> > wrong otherwise. And you really want a separator between the chip name
> > and the id, because "tsl25500" will be confusing as hell.
>
> The length is fine with the restriction above, but I agree we need a separation
> (hadn't really thought this through!).
The length is fine until someone needs more sensors, changes
TSL2550_DEV_MAX to 16, and then the code crashes and nobody knows why.
You can't assume that other developers won't touch your code. Thus it
is much better to handle a given limitation in a single place. Here you
can simply check the value returned by snprintf() and then you know if
your name was correctly set.
Again, not that it matters, because the name buffer should simply be
large enough that it always fits.
--
Jean Delvare
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2009-11-26 14:17 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-09 14:37 [PATCH] ALS: TSL2550 driver move from i2c/chips Jonathan Cameron
2009-10-09 15:05 ` Jonathan Cameron
[not found] ` <4ACF4AC6.7070802-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>
2009-10-09 14:53 ` Jonathan Cameron
2009-10-10 16:33 ` Jean Delvare
[not found] ` <20091010183347.52b043ed-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-10-12 15:13 ` Jonathan Cameron
[not found] ` <4AD3477D.4020904-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org>
2009-10-12 15:38 ` Jean Delvare
[not found] ` <20091012173824.0f3ef021-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-11-26 14:17 ` Jean Delvare
2009-10-10 16:52 ` Jean Delvare
2009-10-12 14:19 ` Jonathan Cameron
2009-10-12 15:52 ` Jean Delvare
[not found] ` <20091012175216.6d844623-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-10-12 17:02 ` Jonathan Cameron
2009-10-12 18:45 ` Jean Delvare
2009-10-16 1:37 ` Zhang Rui
2009-10-16 1:42 ` Zhang Rui
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).