Re: [PATCH v2 2/4] iio: add LM3533 ambient light sensor driver
flat view
From: Jonathan Cameron <hidden>
Date: 2012-05-08 13:47:34
Also in:
linux-iio, lkml
On 5/3/2012 5:36 PM, Johan Hovold wrote:
On Thu, May 03, 2012 at 12:40:10PM +0100, Jonathan Cameron wrote:quoted
On 5/3/2012 11:26 AM, Johan Hovold wrote:quoted
Add sub-driver for the ambient light sensor interface on National Semiconductor / TI LM3533 lighting power chips. The sensor interface can be used to control the LEDs and backlights of the chip through defining five light zones and three sets of corresponding brightness target levels. The driver provides raw and mean adc readings along with the current light zone through sysfs. A threshold event can be generated on zone changes.Code is fine. Pretty much all my comments are to do with the interface.[...]quoted
quoted
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light-lm3533-als b/drivers/staging/iio/Documentation/sysfs-bus-iio-light-lm3533-als new file mode 100644 index 0000000..9849d14 --- /dev/null +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light-lm3533-als@@ -0,0 +1,62 @@ +What: /sys/bus/iio/devices/iio:deviceX/gain +Date: April 2012 +KernelVersion: 3.5 +Contact: Johan Hovold<jhovold@gmail.com> +Description: + Set the ALS gain-resistor setting (0..127) for analog input + mode, where + + 0000000 - ALS input is high impedance + 0000001 - 200kOhm (10uA at 2V full-scale) + 0000010 - 100kOhm (20uA at 2V full-scale) + ... + 1111110 - 1.587kOhm (1.26mA at 2V full-scale) + 1111111 - 1.575kOhm (1.27mA at 2V full-scale) + + R_als = 2V / (10uA * gain) (gain> 0)Firstly, no magic numbers. These are definitely magic.Not that magic as they're clearly documented (in code and public datasheets), right? What would you prefer instead?
The numbers on the right of the - look good to me though then this isn't a gain. (200kohm) and the infinite element is annoying. Why not compute the actual gains? Gain = (Rals*10e-6)/2 and use those values? Yes you will have to do a bit of fixed point maths in the driver but the advantage is you'll have real values that are standardizable across multiple devices and hence allow your device to be operated by generic userspace code. Welcome to standardising interfaces - my favourite occupation ;)
quoted
Secondly see in_illuminance0_scale for a suitable existing attribute.I didn't consider scale to be appropriate given the following documentation (e.g, for in_voltageY_scale):
sorry I just did this to someone else in another review (so I'm consistently wrong!) in_voltageY_calibscale is what I should have said. That one applies a scaling before the raw reading is generated (so in hardware).
"If known for a device, scale to be applied to<type>Y[_name]_raw post addition of<type>[Y][_name]_offset in order to obtain the measured value in<type> units as specified in<type>[Y][_name]_raw documentation." That is, the gain setting has nothing to do with scaling the raw adc reading to SI-units or such, it's simply a setup dependent gain setting (which affects the raw readings as well). [And as such, should probably go into to the platform data eventually as well.]quoted
quoted
+ +What: /sys/bus/iio/devices/iio:deviceX/illuminance_zone +Date: April 2012 +KernelVersion: 3.5 +Contact: Johan Hovold<jhovold@gmail.com> +Description: + Get the current light zone (0..4) as defined by the + in_illuminance_thresh[n]_{falling,rising} thresholds.Hmm.. definitely have an in prefix, beyond that I'm not sure what the cleanestThanks for catching this, it's a typo in the sysfs document -- the in_ prefix is in the code.quoted
interface will be for this. Could extend the event codes to deal with the zone index. Slightly tricky as the channel could already be modified so chan2 isn't necesarily available.quoted
+ +What: /sys/.../events/in_illuminance_thresh_either_en +Date: April 2012 +KernelVersion: 3.5 +Contact: Johan Hovold<jhovold@gmail.com> +Description: + Event generated when channel passes one of the four threshold + in either direction (rising|falling) and a zone change occurs. + The corresponding light zone can be read from + illuminance_zone. + +What: /sys/.../events/illuminance_thresh0_falling_valuehmm.. every time you think you are making progress a new and exciting device comes along requiring the abi to be extended.Exciting isn't it. :)
humph.
quoted
in_illuminanceX_threshY_rising_value in_illuminanceX_threshY_falling_value should do with appropriate description.Ok.quoted
quoted
+What: /sys/.../events/illuminance_thresh0_raising_value +What: /sys/.../events/illuminance_thresh1_falling_value +What: /sys/.../events/illuminance_thresh1_raising_value +What: /sys/.../events/illuminance_thresh2_falling_value +What: /sys/.../events/illuminance_thresh2_raising_value +What: /sys/.../events/illuminance_thresh3_falling_value +What: /sys/.../events/illuminance_thresh3_raising_value +Date: April 2012 +KernelVersion: 3.5 +Contact: Johan Hovold<jhovold@gmail.com> +Description: + Specifies the value of threshold that the device is comparing + against for the events enabled by + in_illuminance_thresh_either_en, and defines the + the five light zones. + + These thresholds correspond to the eight zone-boundary + registers (boundary[n]_{low,high}). +This interface is going to take some thought. We have in_illuminance0_target at the moment, so I guess we can add a zoning concept to that...But target isn't really related, as far as I understand. That's another calibration setting right? While zone is derived from the average adc readings. (More below.)
True enough. I'd missunderstood this.
quoted
quoted
+What: /sys/bus/iio/devices/iio:deviceX/target[m]_[n] +Date: April 2012 +KernelVersion: 3.5 +Contact: Johan Hovold<jhovold@gmail.com> +Description: + Set the target brightness for ALS-mapper m in light zone n + (0..255), where m in 1..3 and n in 0..4.Don't suppose you could do a quick summary of what these zones are and why there are 3 ALS-mappers? I'm not getting terribly far on a quick look at the datasheet!Of course. The average adc readings are mapped to five light zones using eight zone boundary registers (4 boundaries with hysteresis) and a set of rules.
This is going to be fun. We'll need the boundaries and attached hysteresis attributes to fully specify these (nothing would indicate that hysterisis is involved otherwise).
To simplify somewhat (by ignoring some of the rules): If the average adc input drops below boundary0_low, the zone register reads 0; if it drops below boundary1_low, it reads 1, and so on. If the input it increases over boundary3_high, the zone register return 4; if it increases passed boundary2_high, it returns zone 3, etc. That is, roughly something like (we get 8-bits of input from the ADC): zone 0 boundary0_low 51 boundary0_high 53 zone 1 boundary1_low 102 boundary1_high 106 zone 2 boundary2_low 153 boundary2_high 161 zone 3 boundary3_low 204 boundary3_high 220 zone 4 [ Figure 6 on page 20 in the datasheets should make it clear. ] The ALS interface and it's zone concept can then be used to control the LEDs and backlights of the chip, by determining the target brightness for each zone, e.g., set brightness to 52 when in zone 0. To complicate things further (and it is complicated), there are three such sets of target brightness values: ALSM1, ALSM2, ALSM3. So for each LED or backlight you can set ALS-input control mode, by saying that the device should get it's brightness levels from target set 1, 2, or 3. [ And it gets even more complicated, as ALSM1 can only control backlight0, where as ALSM2 and ALSM3 can control any of the remaining devices, but that's irrelevant here. ] Initially, I thought this interface to be too esoteric to be worth generalising, but it sort of fits with event thresholds so I gave it a try.
Glad you did and it pretty much fits, be it with a few extensions being necessary.
The biggest conceptual problem, I think, is that the zone boundaries can be used to control the other devices, even when the event is not enabled (or even an irq line not configured). That is, I find it a bit awkward that the event thresholds also defines the zones (a sort of discrete scaling factor).
That is indeed awkward. I'm not sure how we handle this either. If we need to control these from the other devices (e.g. the back light driver) then we'll have to get them into chan_spec and use the inkernel interfaces to do it. Not infeasible but I was hoping to avoid that until we have had a few months to see what similar devices show up (on basis nothing in this world is a one off for long ;)
Perhaps simply keeping the attributes outside of events (e.g. named
boundary[n]_{low,high}) and having a custom event enabled (e.g.
in_illuminance_zone_change_en) is the best solution?Maybe, but it's ugly and as you have said, they do correspond pretty well to thresholds so I'd rather you went with that. The core stuff for registering events clearly needs a rethink.... For now doing it as you describe above (with the addition fo hysteresis attributes) should be fine. Just document the 'quirks'.
[...]quoted
quoted
diff --git a/drivers/staging/iio/light/lm3533-als.c b/drivers/staging/iio/light/lm3533-als.c new file mode 100644 index 0000000..e2c9be6 --- /dev/null +++ b/drivers/staging/iio/light/lm3533-als.c@@ -0,0 +1,617 @@ +/* + * lm3533-als.c -- LM3533 Ambient Light Sensor driver + * + * Copyright (C) 2011-2012 Texas Instruments + * + * Author: Johan Hovold<jhovold@gmail.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; either version 2 of the License, or (at your + * option) any later version. + */ + +#include<linux/atomic.h> +#include<linux/fs.h> +#include<linux/interrupt.h> +#include<linux/io.h> +#include<linux/module.h> +#include<linux/mfd/core.h> +#include<linux/platform_device.h> +#include<linux/slab.h> +#include<linux/uaccess.h> + +#include<linux/mfd/lm3533.h> + +#include "../events.h" +#include "../iio.h"This will need to go through the staging-next tree. In there these headers have moved.I'm aware of the move. Should the different sub-drivers go in through each tree respectively? Right now the four patches are all against rc5.
They will probably have to. Typically mfd bit goes in first, then the rest get added in a random order after that.
[...]quoted
quoted
+static const struct iio_chan_spec lm3533_als_channels[] = { + { + .type = IIO_LIGHT, + .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT, + .channel = 0,channel doesn't get used unless you also set indexed = 1.So, you mean I could drop channel as well? Or should I add indexed, as I use channel 0 when reporting the event?
Either option is valid. I personally tend to set indexed = 1 but we decided that it didn't matter either way. Userspace code that uses the abi right should allow for either.
[...]quoted
quoted
+static int lm3533_als_set_int_mode(struct iio_dev *indio_dev, int enable) +{ + struct lm3533_als *als = iio_priv(indio_dev); + u8 mask = LM3533_ALS_INT_ENABLE_MASK; + u8 val; + int ret; + + if (enable) + val = mask; + else + val = 0; + + ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, val, mask); + if (ret) { + dev_err(&indio_dev->dev, "failed to set int mode %d\n", + enable);extra brackets.I prefer the brackets for multi-line (single) statements even though they are not required. (Especially if the single statement spans several lines -- but I try to be consistent.) If you have a strong opinion about this, I'll drop them.
I don't care either way.
quoted
quoted
+ } + + return ret; +} +Thanks, Johan