* Re: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver [not found] <1299634342.1785.20.camel@jonz-ubuntu> @ 2011-03-09 19:14 ` Jonathan Cameron 2011-03-12 1:16 ` Jon Brenner 0 siblings, 1 reply; 10+ messages in thread From: Jonathan Cameron @ 2011-03-09 19:14 UTC (permalink / raw) To: Jon Brenner, linux-iio@vger.kernel.org; +Cc: Linux Kernel On 03/09/11 01:32, Jon Brenner wrote: > From: J. August Brenner <jbrenner@taosinc.com> > > This driver supports the TAOS tsl258x family of ALS sensors. > This driver provides ALS data (lux), and device configuration via > isysfs/iio. > More significantly, this driver provides the capability to be fed 'glass > coefficients' to accommodate varying system designs (bezels, faceplates, > etc.). > Jon, Please cc all the relevant subsystem lists...(done) Sorry to say I'm pretty militant about attribute names. My job is to ensure we end up with a generalizable set, consistent across lots of different sensor types. That consistency does restrict what is acceptable a lot more than would be true if we were only interested in light sensors. That's not say I'm not happy to have futher discussions on these points. Otherwise, getting there. Various comments inline. > Signed-off-by: Jon August Brenner <jbrenner@taosinc.com> > > --- > >>>From 5b8364f9828dbad5fbfff96385e3fc2a6a6d56ed Mon Sep 17 00:00:00 2001 > From: Jon Brenner <jbrenner@taosinc.com> > Date: Tue, 8 Mar 2011 18:37:13 -0600 > Subject: [PATCH] TAOS driver for the tsl258x family of devices. This should be in the patch body. Guessing output of git format-patch? It's for use with git send-email and forms the email header. > --- > Makefile | 2 +- > .../staging/iio/Documentation/sysfs-bus-iio-light | 63 ++ > drivers/staging/iio/light/Kconfig | 7 + > drivers/staging/iio/light/Makefile | 1 + > drivers/staging/iio/light/tsl258x.c | 1010 ++++++++++++++++++++ > 5 files changed, 1082 insertions(+), 1 deletions(-) > > diff --git a/Makefile b/Makefile > index 26d7d82..2f7d922 100644 > --- a/Makefile > +++ b/Makefile This shouldn't be in a driver patch. > @@ -1,7 +1,7 @@ > VERSION = 2 > PATCHLEVEL = 6 > SUBLEVEL = 38 > -EXTRAVERSION = -rc6 > +EXTRAVERSION = -rc7 > NAME = Flesh-Eating Bats with Fangs > > # *DOCUMENTATION* > diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/drivers/staging/iio/Documentation/sysfs-bus-iio-light > index 5d84856..5affc2a 100644 > --- a/drivers/staging/iio/Documentation/sysfs-bus-iio-light > +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light > @@ -62,3 +62,66 @@ Description: > sensing mode. This value should be the output from a reading > and if expressed in SI units, should include _input. If this > value is not in SI units, then it should include _raw. > + > +What: /sys/bus/iio/devices/device[n]/device_state > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets the TAOS tsl258x power state. This certainly looks more general than that. It's not light sensor specific so should be in sysfs-bus-iio rather than the light related doc. Having said that it's also a rather non specific description / name. I've been generally pushing against having this sort of power control as an explicit attribute in the iio abi simply because the right way to handle this is probably runtime power management. We did let a few drivers do this early on simply because they predated runtime PM. That framework has the advantage that it also allows for the bus to be turned off if no devices on it need to be talked to. It may be time to reopen the previous discussion of how to allow userspace to explicitly say it doesn't care if a device is powered up... > + > +What: /sys/bus/iio/devices/device[n]/als_gain > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets the TAOS tsl258x analog gain settings > + of the device. Again, please get the mention of particular part out of the description. Although it isn't explicitly specified (yet) for light sensors, we do have an equivalent (I think) of this assuming it is a linear relationship? (google found me a datasheet so at least superficially I think it is). That attribute is illuminance_calibscale (calib bit means it is applied on device or in driver rather than telling userspace what needs to be applied by it). (yikes, just noticed that this is wrong in tsl2563 where we have calibgain due to some inconsistency on my part a while back). Also avoid 'magic' numbers as seen here. There are a finite range of possible values, so have an extra attributes - here illuminance_calibscale_available which is read only and gives the string "1 8 16 111" and make illuminance_calibscale return -EINVAL if the value written is not one of these. sysfs_streq is really handy for this sort of matching. > + > +What: /sys/bus/iio/devices/device[n]/als_time > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets the TAOS tsl258x ADC channel integration > + time in 2.7ms increments. Again, this is more general than just working for the tsl258x driver. That 2.7ms isn't though. Please make this a value in millisecs (fixed point) then deal with conversion to this base in the driver. On this one, it is closely related to the 'period' attributes that exist for various events. Perhaps illuminance_period is a more consistent name? > + > +What: /sys/bus/iio/devices/device[n]/als_trim > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets the TAOS tsl258x ADC active gain scale. This one needs more detail before I can comment. I can't figure out what it actually is! > + > +What: /sys/bus/iio/devices/device[n]/als_target > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets the TAOS tsl258x ADC last known external > + lux measurement used in calibration. als_target -> illuminance0_target lux -> illuminance. What units? Sounds more general than the tsl258x to me so perhaps say that chip is an example of its use? > + > +What: /sys/bus/iio/devices/device[n]/lux > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets the TAOS tsl258x calculated lux value. Sorry, lux is a unit. Attributes are named after what is being measured. Hence illuminance. Might seem reasonable to use the unit, but then what would we do for acceleration (m/s^2)? I guess we can reopen this debate again if you are really attached to lux... Also needs to be illuminance0_input. The input specifices that it is in the base unit (lux) rather than raw. We stick to this form to maintain compatiblity with hwmon which has been around a lot longer than us! > + > +What: /sys/bus/iio/devices/device[n]/lux_table > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets the TAOS tsl258x lux table of coefficients > + that are used to calculate lux. > + > +What: /sys/bus/iio/devices/device[n]/reg_offset > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets an index the TAOS tsl258x internel register > + for r/w of selected register. Sorry, not letting direct register write attributes in. What do you need these for? Can it really not be replaced by more informative attributes? > + > +What: /sys/bus/iio/devices/device[n]/reg_offset > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets an TAOS tsl258x internel register value > + indexed by reg_offset. > + Extra empty lines. Please remove. Also please run checkpatch over this patch. I think there are some extra tabs on these lines that won't have gotten through that. > + > + > \ No newline at end of file > diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig > index 36d8bbe..ae499b8 100644 > --- a/drivers/staging/iio/light/Kconfig > +++ b/drivers/staging/iio/light/Kconfig > @@ -13,6 +13,13 @@ config SENSORS_TSL2563 > This driver can also be built as a module. If so, the module > will be called tsl2563. > > +config TAOS_258x > + tristate "TAOS TSL258x device driver" > + default m > + help > + Provides support for the TAOS tsl258x family of devices. > + Access ALS data/control via sysfs/iio. Please list devices. People tend to grep the tree for the part number of the device that they actually have hence it is useful to have them all explicitly listed here. In combination with the id table listing them all this also tends to tell people if the developer thinks it will work with the part they have. > + > config SENSORS_ISL29018 > tristate "ISL 29018 light and proximity sensor" > depends on I2C > diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile > index 9142c0e..4395db8 100644 > --- a/drivers/staging/iio/light/Makefile > +++ b/drivers/staging/iio/light/Makefile > @@ -3,4 +3,5 @@ > # > > obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o > +obj-$(CONFIG_TAOS_258x) += tsl258x.o > obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o > diff --git a/drivers/staging/iio/light/tsl258x.c b/drivers/staging/iio/light/tsl258x.c > new file mode 100644 > index 0000000..225d85b > --- /dev/null > +++ b/drivers/staging/iio/light/tsl258x.c > @@ -0,0 +1,1010 @@ > +/* > + * Device driver for monitoring ambient light intensity (lux) > + * within the TAOS tsl258x family of devices > + * > + * Copyright (c) 2011, TAOS Corporation. > + * > + * 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. > + * > + * 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., > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + */ > + > +#include <linux/kernel.h> > +#include <linux/i2c.h> > +#include <linux/errno.h> > +#include <linux/delay.h> > +#include <linux/string.h> > +#include <linux/mutex.h> > +#include "../iio.h" > + > +#define DEVICE_ID "tsl258x" > + > +#define MAX_DEVICE_REGS 32 > + I'm guessing this is an internal part name? If possible please replace with the numbers people will see on datasheets. > +/* Triton register offsets */ > +#define TAOS_REG_MAX 8 > + > +/* Device Registers and Masks */ > +#define TSL258X_CNTRL 0x00 This needs a a comment. Why two regs with the same address? > +#define TSL258X_STATUS 0x00 > +#define TSL258X_ALS_TIME 0X01 > +#define TSL258X_INTERRUPT 0x02 > +#define TSL258X_GAIN 0x07 > +#define TSL258X_REVID 0x11 > +#define TSL258X_CHIPID 0x12 Cryptic name and never used. Please remove. > +#define TSL258X_SMB_4 0x13 > +#define TSL258X_ALS_CHAN0LO 0x14 > +#define TSL258X_ALS_CHAN0HI 0x15 > +#define TSL258X_ALS_CHAN1LO 0x16 > +#define TSL258X_ALS_CHAN1HI 0x17 > +#define TSL258X_TMR_LO 0x18 > +#define TSL258X_TMR_HI 0x19 > + > +/* Skate cmd reg masks */ > +#define TSL258X_CMD_REG 0x80 > +#define TSL258X_CMD_BYTE_RW 0x00 This name confuses me. Looks like it sets word protocol so why the block bit? Also not used so could just get rid of it. > +#define TSL258X_CMD_WORD_BLK_RW 0x20 > +#define TSL258X_CMD_SPL_FN 0x60 Nitpick. Later reference to INT have an _ after them. Perhaps add one for consistency? > +#define TSL258X_CMD_ALS_INTCLR 0X01 > + Err. Skate? > +/* Skate cntrl reg masks */ Not used and rather pointless. Default would be to assume writing 0 cleared a register? (or does this mean something else?) > +#define TSL258X_CNTL_REG_CLEAR 0x00 > +#define TSL258X_CNTL_ALS_INT_ENBL 0x10 > +#define TSL258X_CNTL_WAIT_TMR_ENBL 0x08 > +#define TSL258X_CNTL_ADC_ENBL 0x02 > +#define TSL258X_CNTL_PWRON 0x01 > +#define TSL258X_CNTL_ALSPON_ENBL 0x03 Define this in terms of PWRON and ADC_ENBL to make it clear what it is. > +#define TSL258X_CNTL_INTALSPON_ENBL 0x13 also define this in terms of its sub parts. > + > +/* Skate status reg masks */ > +#define TSL258X_STA_ADCVALID 0x01 > +#define TSL258X_STA_ALSINTR 0x10 > +#define TSL258X_STA_ADCINTR 0x10 > + > +/* Lux constants */ > +#define MAX_LUX 65535 Err. Rename that unless it really does mean 65535 lux > + > +enum { > + TAOS_CHIP_UNKNOWN = 0, TAOS_CHIP_WORKING = 1, TAOS_CHIP_SLEEP = 2 > +} TAOS_CHIP_WORKING_STATUS; > + > +/* Per-device data */ > +struct taos_als_info { > + u16 als_ch0; > + u16 als_ch1; > + u16 lux; > +}; > + > +struct taos_settings { > + int als_time; > + int als_gain; > + int als_gain_trim; > + int als_cal_target; > +}; > + > +struct tsl258x_chip { > + struct mutex als_mutex; > + struct i2c_client *client; > + struct iio_dev *iio_dev; > + struct delayed_work update_lux; > + unsigned int addr; > + char taos_id; > + char valid; > + unsigned long last_updated; > + struct taos_als_info als_cur_info; > + struct taos_settings taos_settings; > + int als_time_scale; > + int als_saturation; > + int taos_chip_status; > + u8 taos_config[8]; > +}; > + > +static int taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, > + unsigned int len); > +static int taos_i2c_write_command(struct i2c_client *client, u8 reg); > + > +/* > + * Initial values for device - this values can/will be changed by driver. > + * and applications as needed. > + * These values are dynamic. > + */ > +static const u8 taos_config[8] = { > + 0x00, 0xee, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x00 > +}; /* cntrl atime intC Athl0 Athl1 Athh0 Athh1 gain */ > + > +struct taos_lux { > + unsigned int ratio; > + unsigned int ch0; > + unsigned int ch1; > +}; > + > +/* This structure is intentionally large to accommodate updates via sysfs. */ > +/* Sized to 11 = max 10 segments + 1 termination segment */ Any chance of two sensors on one device, each of which has different values for this? > +struct taos_lux taos_device_lux[11] = { > + { 9830, 8520, 15729 }, > + { 12452, 10807, 23344 }, > + { 14746, 6383, 11705 }, > + { 17695, 4063, 6554 }, > +}; > + > +struct taos_lux taos_lux; > + > +struct gainadj { > + s16 ch0; > + s16 ch1; > +}; > + > +/* Index = (0 - 3) Used to validate the gain selection index */ > +static const struct gainadj gainadj[] = { > + { 1, 1 }, > + { 8, 8 }, > + { 16, 16 }, That's 'interesting'. This will make the calibscale discussion above more complex. I guess no userspace is going to care about the precise internal multipliers so a 'rough' value would probably do in that attribute. What do you think? > + { 107, 115 } > +}; > + > +/* > + * Provides initial operational parameter defaults. > + * These defaults may be changed through the device's sysfs files. > + */ > +static void taos_defaults(struct tsl258x_chip *chip) > +{ > + /* Operational parameters */ > + chip->taos_settings.als_time = 450; > + /* must be a multiple of 50mS */ > + chip->taos_settings.als_gain = 2; > + /* this is actually an index into the gain table */ > + /* assume clear glass as default */ > + chip->taos_settings.als_gain_trim = 1000; > + /* default gain trim to account for aperture effects */ > + chip->taos_settings.als_cal_target = 130; > + /* Known external ALS reading used for calibration */ > + > + /* Initialize ALS data to defaults */ > + chip->als_cur_info.als_ch0 = 0; > + chip->als_cur_info.als_ch1 = 0; > + chip->als_cur_info.lux = 0; Already zero via the memset (soon to be kzalloc) hence don't bother setting these three. > +} > + > +/* > + * Read a number of bytes starting at register (reg) location. > + * Return 0, or i2c_smbus_write_byte ERROR code. > + */ > +static int > +taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, unsigned int len) > +{ > + int ret; > + int i; > + > + for (i = 0; i < len; i++) { > + /* select register to write */ > + ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | reg)); > + if (ret < 0) { > + dev_err(&client->dev, "taos_i2c_read failed to write" > + " register %x\n", reg); > + return ret; > + } > + /* read the data */ > + *val = i2c_smbus_read_byte(client); I'd use val[i] without this increment for clarity. > + val++; > + if ((reg & 0x1f) == 0x1f) Can this ever occcur in the driver? I would imagine it is a bug if it does as you'll read back a different number of values than you expect to do. If not it's an over enthusiastic bit of debug code so get rid of it. > + break; > + reg++; > + } > + return 0; > +} > + > +/* > + * This function is used to send a command to device command/control register > + * All bytes sent using this command have their MSBit set - it's a command! > + * Return 0, or i2c_smbus_write_byte error code. > + */ > +static int taos_i2c_write_command(struct i2c_client *client, u8 reg) > +{ > + int ret; > + > + /* write the data */ > + ret = i2c_smbus_write_byte(client, (reg |= TSL258X_CMD_REG)); > + if (ret < 0) { > + dev_err(&client->dev, "FAILED: i2c_smbus_write_byte\n"); > + return ret; > + } > + return 0; > +} > + > +/* > + * Reads and calculates current lux value. > + * The raw ch0 and ch1 values of the ambient light sensed in the last > + * integration cycle are read from the device. > + * Time scale factor array values are adjusted based on the integration time. > + * The raw values are multiplied by a scale factor, and device gain is obtained > + * using gain index. Limit checks are done next, then the ratio of a multiple > + * of ch1 value, to the ch0 value, is calculated. The array taos_device_lux[] > + * declared above is then scanned to find the first ratio value that is just > + * above the ratio we just calculated. The ch0 and ch1 multiplier constants in > + * the array are then used along with the time scale factor array values, to > + * calculate the lux. > + */ > +static int taos_get_lux(struct i2c_client *client) > +{ > + u32 ch0, ch1; /* separated ch0/ch1 data from device */ > + u32 lux; /* raw lux calculated from device data */ And here we have a great example of why lux is a bad name for this. lux could only ever have units of lux. > + u32 ratio; > + u8 buf[5]; > + struct taos_lux *p; > + struct tsl258x_chip *chip = i2c_get_clientdata(client); > + int i, ret; > + u32 ch0lux = 0; > + u32 ch1lux = 0; > + > + if (mutex_trylock(&chip->als_mutex) == 0) { > + dev_info(&client->dev, "taos_get_lux device is busy\n"); > + return chip->als_cur_info.lux; /* busy, so return LAST VALUE */ > + } > + > + if (chip->taos_chip_status != TAOS_CHIP_WORKING) { > + /* device is not enabled */ > + dev_err(&client->dev, "taos_get_lux device is not enabled\n"); > + ret = -ENODEV; -EBUSY probably. The device exists, it's just turned off. > + goto out_unlock; > + } > + > + ret = taos_i2c_read(client, (TSL258X_CMD_REG), &buf[0], 1); > + if (ret < 0) { > + dev_err(&client->dev, "taos_get_lux failed to read CMD_REG\n"); > + goto out_unlock; > + } > + /* is data new & valid */ > + if (!(buf[0] & TSL258X_STA_ADCINTR)) { > + dev_err(&client->dev, "taos_get_lux data not valid\n"); I'd error out at this point. Something has gone wrong and you want to indicate it to your userspace code. > + ret = chip->als_cur_info.lux; /* return LAST VALUE */ > + goto out_unlock; > + } > + > + for (i = 0; i < 4; i++) { > + int reg = TSL258X_CMD_REG | (TSL258X_ALS_CHAN0LO + i); > + ret = taos_i2c_read(client, reg, &buf[i], 1); > + if (ret < 0) { > + dev_err(&client->dev, "taos_get_lux failed to read" > + " register %x\n", reg); > + goto out_unlock; > + } > + } > + > + /* clear status, really interrupt status (interrupts are off), but > + * we use the bit anyway */ > + ret = taos_i2c_write_command(client, > + TSL258X_CMD_REG | TSL258X_CMD_SPL_FN | TSL258X_CMD_ALS_INTCLR); > + if (ret < 0) { > + dev_err(&client->dev, This is the one case where checkpatch warnings should be ignored. Please keep strings like this on a single line as people who see them in a log will grep for them in the source code. Artificial breaks like this make them a lot harder to find! > + "taos_i2c_write_command failed in " > + "taos_get_lux, err = %d\n", ret); > + goto out_unlock; /* have no data, so return failure */ > + } > + > + /* extract ALS/lux data */ Should be the relevant endian conversion function. be16tocpu or similar (haven't thought about which). That way it's free on one endianness of machine. > + ch0 = (buf[1] << 8) | buf[0]; > + ch1 = (buf[3] << 8) | buf[2]; > + > + chip->als_cur_info.als_ch0 = ch0; > + chip->als_cur_info.als_ch1 = ch1; > + > + if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) > + goto return_max; > + > + if (ch0 == 0) { > + /* have no data, so return LAST VALUE */ > + ret = chip->als_cur_info.lux = 0; > + goto out_unlock; > + } > + /* calculate ratio */ > + ratio = (ch1 << 15) / ch0; > + /* convert to unscaled lux using the pointer to the table */ > + for (p = (struct taos_lux *) taos_device_lux; > + p->ratio != 0 && p->ratio < ratio; p++) > + ; > + > + if (p->ratio == 0) { > + lux = 0; > + } else { > + ch0lux = ((ch0 * p->ch0) + > + (gainadj[chip->taos_settings.als_gain].ch0 >> 1)) > + / gainadj[chip->taos_settings.als_gain].ch0; > + ch1lux = ((ch1 * p->ch1) + > + (gainadj[chip->taos_settings.als_gain].ch1 >> 1)) > + / gainadj[chip->taos_settings.als_gain].ch1; > + lux = ch0lux - ch1lux; > + } > + > + /* note: lux is 31 bit max at this point */ > + if (ch1lux > ch0lux) { > + dev_dbg(&client->dev, "No Data - Return last value\n"); Again, do we want userspace to know the sensor isn't returning valid values? > + ret = chip->als_cur_info.lux = 0; > + goto out_unlock; > + } > + > + /* adjust for active time scale */ > + if (chip->als_time_scale == 0) > + lux = 0; > + else > + lux = (lux + (chip->als_time_scale >> 1)) / > + chip->als_time_scale; > + > + /* adjust for active gain scale */ > + lux >>= 13; /* tables have factor of 8192 builtin for accuracy */ > + lux = (lux * chip->taos_settings.als_gain_trim + 500) / 1000; > + if (lux > MAX_LUX) { /* check for overflow */ > +return_max: > + lux = MAX_LUX; Really the right thing to do? Surely you want to return an out of range error? Perhaps ERANGE so userspace knows the value is garbage. > + } > + > + /* Update the structure with the latest VALID lux. */ > + chip->als_cur_info.lux = lux; > + ret = lux; > + > +out_unlock: > + mutex_unlock(&chip->als_mutex); > + return ret; > +} > + > +/* > + * Obtain single reading and calculate the als_gain_trim (later used > + * to derive actual lux). > + * Return updated gain_trim value. > + */ > +int taos_als_calibrate(struct i2c_client *client) > +{ > + struct tsl258x_chip *chip = i2c_get_clientdata(client); > + u8 reg_val; > + unsigned int gain_trim_val; > + int ret; > + int lux_val; > + > + ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | TSL258X_CNTRL)); > + if (ret < 0) { > + dev_err(&client->dev, "taos_als_calibrate failed to reach the" Again, don't break this sort of string up however much checkpatch rants at you. > + " CNTRL register, ret=%d\n", ret); > + return ret; > + } > + > + reg_val = i2c_smbus_read_byte(client); > + if ((reg_val & (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWRON)) > + != (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWRON)) { > + dev_err(&client->dev, "taos_als_calibrate failed because the" > + " device is not powered on with ADC enabled\n"); > + return -ENODATA; > + } > + > + ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | TSL258X_STATUS)); > + if (ret < 0) { > + dev_err(&client->dev, "taos_als_calibrate failed to reach the" > + " STATUS register, ret=%d\n", ret); > + return ret; > + } > + reg_val = i2c_smbus_read_byte(client); > + > + if ((reg_val & TSL258X_STA_ADCVALID) != TSL258X_STA_ADCVALID) { > + dev_err(&client->dev, "taos_als_calibrate failed because the" > + " STATUS did not indicate ADC valid.\n"); > + return -ENODATA; > + } > + lux_val = taos_get_lux(client); > + if (lux_val < 0) { > + dev_err(&client->dev, "taos_als_calibrate failed to get lux\n"); > + return lux_val; > + } > + gain_trim_val = (unsigned int) (((chip->taos_settings.als_cal_target) > + * chip->taos_settings.als_gain_trim) / lux_val); > + > + dev_info(&client->dev, "taos_settings.als_cal_target = %d\n" > + "taos_settings.als_gain_trim = %d\nlux_val = %d\n", > + chip->taos_settings.als_cal_target, > + chip->taos_settings.als_gain_trim, > + lux_val); > + > + if ((gain_trim_val < 250) || (gain_trim_val > 4000)) { > + dev_err(&client->dev, "taos_als_calibrate failed because" > + "trim_val of %d is out of range\n", gain_trim_val); > + return -ENODATA; > + } > + chip->taos_settings.als_gain_trim = (int) gain_trim_val; > + > + return (int) gain_trim_val; > +} > + > +/* > + * Turn the device on. > + * Configuration must be set before calling this function. > + */ > +static int taos_chip_on(struct i2c_client *client) > +{ > + int i; > + int ret = 0; > + u8 *uP; > + u8 utmp; > + int als_count; > + int als_time; > + struct tsl258x_chip *chip = i2c_get_clientdata(client); > + and? > + /* and make sure we're not already on */ > + if (chip->taos_chip_status == TAOS_CHIP_WORKING) { > + /* if forcing a register update - turn off, then on */ > + dev_info(&client->dev, "device is already enabled\n"); Not sure what the right error is here, but should be more specific than that. > + return -1; > + } > + > + /* determine als integration regster */ > + als_count = (chip->taos_settings.als_time * 100 + 135) / 270; > + if (als_count == 0) > + als_count = 1; /* ensure at least one cycle */ > + > + > + /* convert back to time (encompasses overrides) */ > + als_time = (als_count * 27 + 5) / 10; > + chip->taos_config[TSL258X_ALS_TIME] = 256 - als_count; > + > + Bonus blank lines. One is plenty to break up code. > + /* Set the gain based on taos_settings struct */ > + chip->taos_config[TSL258X_GAIN] = chip->taos_settings.als_gain; > + > + > + /* set globals re scaling and saturation */ They aren't globals > + chip->als_saturation = als_count * 922; /* 90% of full scale */ > + chip->als_time_scale = (als_time + 25) / 50; > + > + /* SKATE Specific power-on / adc enable sequence > + * Power on the device 1st. */ > + utmp = TSL258X_CNTL_PWRON; > + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG | TSL258X_CNTRL, > + utmp); > + if (ret < 0) { > + dev_err(&client->dev, "taos_chip_on failed on CNTRL reg.\n"); > + return -1; > + } > + > + /* Use the following shadow copy for our delay before enabling ADC. > + * Write all the registers. */ > + for (i = 0, uP = chip->taos_config; i < TAOS_REG_MAX; i++) { > + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG + i, > + *uP++); > + if (ret < 0) { > + dev_err(&client->dev, > + "taos_chip_on failed on reg %d.\n", i); > + return -1; > + } > + } > + > + mdelay(3); > + /* NOW enable the ADC > + * initialize the desired mode of operation */ > + utmp = TSL258X_CNTL_PWRON | TSL258X_CNTL_ADC_ENBL; > + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG | TSL258X_CNTRL, > + utmp); > + if (ret < 0) { > + dev_err(&client->dev, "taos_chip_on failed on 2nd CTRL reg.\n"); > + return -1; > + } > + chip->taos_chip_status = TAOS_CHIP_WORKING; Comment is rather obvious... > + return ret; /* returns result of last i2cwrite */ > +} > + > +/* Turn the device OFF. */ > +static int taos_chip_off(struct i2c_client *client) > +{ > + struct tsl258x_chip *chip = i2c_get_clientdata(client); > + int ret; > + u8 utmp; > + > + /* turn device off */ > + chip->taos_chip_status = TAOS_CHIP_SLEEP; > + utmp = 0x00; > + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG | TSL258X_CNTRL, > + utmp); > + return ret; > +} > + > +/* Sysfs Interface Functions */ > +static ssize_t taos_device_id(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + return sprintf(buf, "%s\n", DEVICE_ID); > +} > + > +static ssize_t taos_power_state_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%d\n", chip->taos_chip_status); > +} > + > +static ssize_t taos_power_state_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + unsigned long value; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + if (value == 0) > + taos_chip_off(chip->client); > + else > + taos_chip_on(chip->client); > + > + return len; > +} > + > +static ssize_t taos_gain_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%d\n", chip->taos_settings.als_gain); > +} > + > +static ssize_t taos_gain_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + unsigned long value; > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + if (value) { > + if (value > 4) { > + dev_err(dev, "Invalid Gain Index\n"); > + return -1; EINVAL > + } else { > + chip->taos_settings.als_gain = value; > + } So this sets the value in the local cache. When does it get written to the device? > + } > + return len; > +} > + > +static ssize_t taos_als_time_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%d\n", chip->taos_settings.als_time); > +} > + > +static ssize_t taos_als_time_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + unsigned long value; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + if (value) > + chip->taos_settings.als_time = value; else? It's not been sucessfuly set so return -EINVAL > + > + return len; > +} > + > +static ssize_t taos_als_trim_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%d\n", chip->taos_settings.als_gain_trim); > +} > + > +static ssize_t taos_als_trim_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + unsigned long value; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + if (value) > + chip->taos_settings.als_gain_trim = value; else return -EINVAL > + > + return len; > +} > + > +static ssize_t taos_als_cal_target_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%d\n", chip->taos_settings.als_cal_target); > +} > + > +static ssize_t taos_als_cal_target_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + unsigned long value; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + if (value) > + chip->taos_settings.als_cal_target = value; again, else return -EINVAL; Userspace really wants to know this failed. > + > + return len; > +} > + > +static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr, > + char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + int lux = 0; no need to assign. > + > + lux = taos_get_lux(chip->client); > + > + return sprintf(buf, "%d\n", lux); > +} > + > +static ssize_t taos_do_calibrate(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + unsigned long value; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + if (value == 1) > + taos_als_calibrate(chip->client); else return -EINVAL; > + > + return len; > +} > + > +static ssize_t taos_luxtable_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + int i; > + int offset = 0; > + > + for (i = 0; i < ARRAY_SIZE(taos_device_lux); i++) { > + offset += sprintf(buf + offset, "%d,%d,%d,", > + taos_device_lux[i].ratio, > + taos_device_lux[i].ch0, > + taos_device_lux[i].ch1); > + if (taos_device_lux[i].ratio == 0) { > + /* We just printed the first "0" entry. > + * Now get rid of the extra "," and break. */ > + offset--; > + break; > + } > + } > + > + offset += sprintf(buf + offset, "\n"); > + return offset; > +} > + > +static ssize_t taos_luxtable_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > +#define MAX_LUX_TABLE_FIELDS 33 I'd loose this define. > + int value[MAX_LUX_TABLE_FIELDS]; > + int n; > + > + get_options(buf, ARRAY_SIZE(value), value); > + > + /* We now have an array of ints starting at value[1], and > + * enumerated by value[0]. > + * We expect each group of three ints is one table entry, > + * and the last table entry is all 0. > + */ > + n = value[0]; prefer to see ARRAY_SIZE(value) than the define. > + if ((n % 3) || n < 6 || n > (MAX_LUX_TABLE_FIELDS - 3)) { > + dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n); > + return -EINVAL; > + } > + if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) { > + dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n); > + return -EINVAL; > + } > + > + if (chip->taos_chip_status == TAOS_CHIP_WORKING) > + taos_chip_off(chip->client); > + > + /* Zero out the table */ > + memset(taos_device_lux, 0, sizeof(taos_device_lux)); > + memcpy(taos_device_lux, &value[1], (value[0] * 4)); > + > + taos_chip_on(chip->client); > + > + return len; > +} > + > +static u8 reg_index; > + As stated above these need to go before we take this driver. > +/* Sets a pointer to a register for R/W via sysfs */ > +static ssize_t taos_reg_offset_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + return sprintf(buf, "%d\n", reg_index); > + return 0; > +} > + > +static ssize_t taos_reg_offset_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + unsigned long value; > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + if (value > MAX_DEVICE_REGS) { > + dev_err(dev, "register offset exceeds MAX\n"); > + return -1; > + } else { > + reg_index = value; > + } > +return len; > +} > + > +/* R/W a register for R/W via sysfs */ > +static ssize_t taos_reg_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + > + u8 value = 0; > + int ret = 0; > + > + ret = i2c_smbus_write_byte(chip->client, > + (TSL258X_CMD_REG | reg_index)); > + if (ret < 0) { > + dev_err(dev, "i2c_smbus_write_byte to cmd reg failed " > + "in taos_reg_offset_show(), err = %d\n", ret); > + return ret; > + } > + value = i2c_smbus_read_byte(chip->client); > + return sprintf(buf, "%d\n", value); > + > +return 0; > +} > + > +static ssize_t taos_reg_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl258x_chip *chip = indio_dev->dev_data; > + > + unsigned long value = 0; > + int ret = 0; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + ret = i2c_smbus_write_byte_data(chip->client, > + (TSL258X_CMD_REG | reg_index), value); > + if (ret < 0) { > + dev_err(dev, "i2c_smbus_write_byte_data failed in " > + "taos_reg_store()\n"); > + return ret; > + } > + > +return len; > +} > + > +static DEVICE_ATTR(name, S_IRUGO, taos_device_id, NULL); > +static DEVICE_ATTR(device_state, S_IRUGO | S_IWUSR, > + taos_power_state_show, taos_power_state_store); > +static DEVICE_ATTR(als_gain, S_IRUGO | S_IWUSR, > + taos_gain_show, taos_gain_store); > +static DEVICE_ATTR(als_time, S_IRUGO | S_IWUSR, > + taos_als_time_show, taos_als_time_store); > +static DEVICE_ATTR(als_trim, S_IRUGO | S_IWUSR, > + taos_als_trim_show, taos_als_trim_store); > +static DEVICE_ATTR(als_target, S_IRUGO | S_IWUSR, > + taos_als_cal_target_show, taos_als_cal_target_store); > +static DEVICE_ATTR(lux, S_IRUGO, taos_lux_show, NULL); > +static DEVICE_ATTR(calibrate, S_IWUSR, NULL, taos_do_calibrate); > +static DEVICE_ATTR(lux_table, S_IRUGO | S_IWUSR, > + taos_luxtable_show, taos_luxtable_store); > +static DEVICE_ATTR(reg_offset, S_IRUGO | S_IWUSR, > + taos_reg_offset_show, > + taos_reg_offset_store); > +static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, > + taos_reg_show, > + taos_reg_store); > + > + > +static struct attribute *sysfs_attrs_ctrl[] = { > + &dev_attr_name.attr, > + &dev_attr_device_state.attr, > + &dev_attr_als_gain.attr, > + &dev_attr_als_time.attr, > + &dev_attr_als_trim.attr, > + &dev_attr_als_target.attr, > + &dev_attr_lux.attr, > + &dev_attr_calibrate.attr, > + &dev_attr_lux_table.attr, Spaces instead of tab here. > + &dev_attr_reg_offset.attr, > + &dev_attr_reg.attr, > + NULL > +}; > + > +static struct attribute_group tsl258x_attribute_group = { > + .attrs = sysfs_attrs_ctrl, > +}; > + > +/* Use the default register values to identify the Taos device */ > +static int taos_skate_device(unsigned char *bufp) > +{ > + if (((bufp[TSL258X_CHIPID] & 0xf0) == 0x90)) > + /* tsl258x */ > + return 1; > + /* else unknown */ > + return 0; > +} > + > +/* > + * Client probe function - When a valid device is found, the driver's device > + * data structure is updated, and initialization completes successfully. > + */ > +static int __devinit taos_probe(struct i2c_client *clientp, > + const struct i2c_device_id *idp) > +{ > + int i, ret = 0; > + unsigned char buf[MAX_DEVICE_REGS]; > + static struct tsl258x_chip *chip; > + > + if (!i2c_check_functionality(clientp->adapter, > + I2C_FUNC_SMBUS_BYTE_DATA)) { > + dev_err(&clientp->dev, > + "taos_probe() - i2c smbus byte data " > + "functions unsupported\n"); > + return -EOPNOTSUPP; > + } > + if (!i2c_check_functionality(clientp->adapter, > + I2C_FUNC_SMBUS_WORD_DATA)) { > + dev_warn(&clientp->dev, > + "taos_probe() - i2c smbus word data " > + "functions unsupported\n"); > + } > + if (!i2c_check_functionality(clientp->adapter, > + I2C_FUNC_SMBUS_BLOCK_DATA)) { > + dev_err(&clientp->dev, > + "taos_probe() - i2c smbus block data " > + "functions unsupported\n"); > + } > + > + chip = kmalloc(sizeof(struct tsl258x_chip), GFP_KERNEL); > + if (!chip) { > + dev_err(&clientp->dev, "taos_device_drvr: kmalloc for " > + "struct tsl258x_chip failed in taos_probe()\n"); > + return -ENOMEM; > + } > + memset(chip, 0, sizeof(struct tsl258x_chip)); Use kzalloc instead of kmalloc then you don't need the memset. > + chip->client = clientp; > + i2c_set_clientdata(clientp, chip); > + > + mutex_init(&chip->als_mutex); > + chip->taos_chip_status = TAOS_CHIP_UNKNOWN; /* uninitialized to start */ > + memcpy(chip->taos_config, taos_config, sizeof(chip->taos_config)); > + > + for (i = 0; i < MAX_DEVICE_REGS; i++) { > + ret = i2c_smbus_write_byte(clientp, > + (TSL258X_CMD_REG | (TSL258X_CNTRL + i))); > + if (ret < 0) { > + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd " > + "reg failed in taos_probe(), err = %d\n", ret); > + goto fail1; > + } > + buf[i] = i2c_smbus_read_byte(clientp); > + } > + if (!taos_skate_device(buf)) { > + dev_info(&clientp->dev, "i2c device found but does not match " > + "expected id in taos_probe()\n"); > + goto fail1; > + } else { > + dev_info(&clientp->dev, "i2c device match in probe\n"); > + } > + ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | TSL258X_CNTRL)); > + if (ret < 0) { > + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg " > + "failed in taos_probe(), err = %d\n", ret); > + goto fail1; > + } > + chip->valid = 0; > + > + chip->iio_dev = iio_allocate_device(); > + if (!chip->iio_dev) { > + ret = -ENOMEM; > + dev_err(&clientp->dev, "iio allocation failed\n"); > + goto fail1; > + } > + > + chip->iio_dev->attrs = &tsl258x_attribute_group; > + chip->iio_dev->dev.parent = &clientp->dev; > + chip->iio_dev->dev_data = (void *)(chip); > + chip->iio_dev->driver_module = THIS_MODULE; > + chip->iio_dev->modes = INDIO_DIRECT_MODE; > + ret = iio_device_register(chip->iio_dev); > + if (ret) { > + dev_err(&clientp->dev, "iio registration failed\n"); > + goto fail1; > + } > + > + /* Load up the V2 defaults (these are hard coded defaults for now) */ > + taos_defaults(chip); > + > + /* Make sure the chip is on */ > + taos_chip_on(clientp); > + > + dev_info(&clientp->dev, "Light sensor found.\n"); > + return 0; > + > +fail1: > + kfree(chip); > + > + return ret; > +} > + > +static int __devexit taos_remove(struct i2c_client *client) > +{ > + struct tsl258x_chip *chip = i2c_get_clientdata(client); > + > + iio_device_unregister(chip->iio_dev); > + > + kfree(chip); > + return 0; > +} > + > +static struct i2c_device_id taos_idtable[] = { > + { DEVICE_ID, 0 }, > + {} Please can we have an explicit list if ID's here. If a person has a tsl2580 then they'll want to say that in their board file. On that note, I skipped this originally as there were bigger fish to fry, but can we be sure that there will never be a value of x that this driver won't work for? If not, please follow convention and pick your favourite part number from the range and replace all x's in the driver appropriately. Too many part manufacturers have really weird naming schemes that tend to break wild cards like this! > +}; > +MODULE_DEVICE_TABLE(i2c, taos_idtable); > + > +/* Driver definition */ > +static struct i2c_driver taos_driver = { > + .driver = { > + .name = "tsl258x", > + }, > + .id_table = taos_idtable, > + .probe = taos_probe, > + .remove = __devexit_p(taos_remove), > +}; > + > +static int __init taos_init(void) > +{ > + return i2c_add_driver(&taos_driver); > +} > + > +static void __exit taos_exit(void) > +{ > + i2c_del_driver(&taos_driver); > +} > + > +module_init(taos_init); > +module_exit(taos_exit); > + > +MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>"); > +MODULE_DESCRIPTION("TAOS tsl258x ambient light sensor driver"); > +MODULE_LICENSE("GPL"); > + ^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver 2011-03-09 19:14 ` [PATCH 2.6.38-rc7]TAOS 258x: Device Driver Jonathan Cameron @ 2011-03-12 1:16 ` Jon Brenner 0 siblings, 0 replies; 10+ messages in thread From: Jon Brenner @ 2011-03-12 1:16 UTC (permalink / raw) To: Jonathan Cameron, linux-iio; +Cc: linux-kernel Sm9oYXRoYW4gLCBldCBhbC4sDQpUaGFuayB5b3UgZm9yIHRha2luZyB0aGUgdGltZSB0byByZXZp ZXcuDQpQbGVhc2Ugc2VlIHJlc3BvbnNlIChJTiBBTEwgQ0FQUykgdG8gdmFyaW91cyBjb21tZW50 cyBpbmxpbmUuIA0KDQpKb24gQnJlbm5lcg0KLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCkZy b206IEpvbmF0aGFuIENhbWVyb24gW21haWx0bzpqaWMyM0BjYW0uYWMudWtdIA0KU2VudDogV2Vk bmVzZGF5LCBNYXJjaCAwOSwgMjAxMSAxOjE0IFBNDQpUbzogSm9uIEJyZW5uZXI7IGxpbnV4LWlp b0B2Z2VyLmtlcm5lbC5vcmcNCkNjOiBMaW51eCBLZXJuZWwNClN1YmplY3Q6IFJlOiBbUEFUQ0gg Mi42LjM4LXJjN11UQU9TIDI1OHg6IERldmljZSBEcml2ZXINCg0KT24gMDMvMDkvMTEgMDE6MzIs IEpvbiBCcmVubmVyIHdyb3RlOg0KPiBGcm9tOiBKLiBBdWd1c3QgQnJlbm5lciA8amJyZW5uZXJA dGFvc2luYy5jb20+DQo+IA0KPiBUaGlzIGRyaXZlciBzdXBwb3J0cyB0aGUgVEFPUyB0c2wyNTh4 IGZhbWlseSBvZiBBTFMgc2Vuc29ycy4NCj4gVGhpcyBkcml2ZXIgcHJvdmlkZXMgQUxTIGRhdGEg KGx1eCksIGFuZCBkZXZpY2UgY29uZmlndXJhdGlvbiB2aWEgDQo+IGlzeXNmcy9paW8uDQo+IE1v cmUgc2lnbmlmaWNhbnRseSwgdGhpcyBkcml2ZXIgcHJvdmlkZXMgdGhlIGNhcGFiaWxpdHkgdG8g YmUgZmVkIA0KPiAnZ2xhc3MgY29lZmZpY2llbnRzJyB0byBhY2NvbW1vZGF0ZSB2YXJ5aW5nIHN5 c3RlbSBkZXNpZ25zIChiZXplbHMsIA0KPiBmYWNlcGxhdGVzLCBldGMuKS4NCj4gDQpKb24sIA0K DQpQbGVhc2UgY2MgYWxsIHRoZSByZWxldmFudCBzdWJzeXN0ZW0gbGlzdHMuLi4oZG9uZSkNCg0K U29ycnkgdG8gc2F5IEknbSBwcmV0dHkgbWlsaXRhbnQgYWJvdXQgYXR0cmlidXRlIG5hbWVzLg0K TXkgam9iIGlzIHRvIGVuc3VyZSB3ZSBlbmQgdXAgd2l0aCBhIGdlbmVyYWxpemFibGUgc2V0LCBj b25zaXN0ZW50IGFjcm9zcyBsb3RzIG9mIGRpZmZlcmVudCBzZW5zb3IgdHlwZXMuICBUaGF0IGNv bnNpc3RlbmN5IGRvZXMgcmVzdHJpY3Qgd2hhdCBpcyBhY2NlcHRhYmxlIGEgbG90IG1vcmUgdGhh biB3b3VsZCBiZSB0cnVlIGlmIHdlIHdlcmUgb25seSBpbnRlcmVzdGVkIGluIGxpZ2h0IHNlbnNv cnMuICBUaGF0J3Mgbm90IHNheSBJJ20gbm90IGhhcHB5IHRvIGhhdmUgZnV0aGVyIGRpc2N1c3Np b25zIG9uIHRoZXNlIHBvaW50cy4NCg0KT3RoZXJ3aXNlLCBnZXR0aW5nIHRoZXJlLiBWYXJpb3Vz IGNvbW1lbnRzIGlubGluZS4NCg0KPiBTaWduZWQtb2ZmLWJ5OiBKb24gQXVndXN0IEJyZW5uZXIg PGpicmVubmVyQHRhb3NpbmMuY29tPg0KPiANCj4gLS0tDQo+IA0KPj5Gcm9tIDViODM2NGY5ODI4 ZGJhZDVmYmZmZjk2Mzg1ZTNmYzJhNmE2ZDU2ZWQgTW9uIFNlcCAxNyAwMDowMDowMCAyMDAxDQo+ IEZyb206IEpvbiBCcmVubmVyIDxqYnJlbm5lckB0YW9zaW5jLmNvbT4NCj4gRGF0ZTogVHVlLCA4 IE1hciAyMDExIDE4OjM3OjEzIC0wNjAwDQo+IFN1YmplY3Q6IFtQQVRDSF0gVEFPUyBkcml2ZXIg Zm9yIHRoZSB0c2wyNTh4IGZhbWlseSBvZiBkZXZpY2VzLg0KVGhpcyBzaG91bGQgYmUgaW4gdGhl IHBhdGNoIGJvZHkuICBHdWVzc2luZyBvdXRwdXQgb2YgZ2l0IGZvcm1hdC1wYXRjaD8NCkl0J3Mg Zm9yIHVzZSB3aXRoIGdpdCBzZW5kLWVtYWlsIGFuZCBmb3JtcyB0aGUgZW1haWwgaGVhZGVyLg0K IA0KV0lMTCBCRSBSRU1PVkVEIEZST00gTkVYVCBQQVRDSCBTVUJNSVNTSU9OIC0gRk9MTE9XSU5H IFRISVMgUkVTUE9OU0UgVE8gQ09NTUVOVA0KDQo+IC0tLQ0KPiAgTWFrZWZpbGUgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAyICstDQo+ICAuLi4vc3RhZ2lu Zy9paW8vRG9jdW1lbnRhdGlvbi9zeXNmcy1idXMtaWlvLWxpZ2h0ICB8ICAgNjMgKysNCj4gIGRy aXZlcnMvc3RhZ2luZy9paW8vbGlnaHQvS2NvbmZpZyAgICAgICAgICAgICAgICAgIHwgICAgNyAr DQo+ICBkcml2ZXJzL3N0YWdpbmcvaWlvL2xpZ2h0L01ha2VmaWxlICAgICAgICAgICAgICAgICB8 ICAgIDEgKw0KPiAgZHJpdmVycy9zdGFnaW5nL2lpby9saWdodC90c2wyNTh4LmMgICAgICAgICAg ICAgICAgfCAxMDEwICsrKysrKysrKysrKysrKysrKysrDQo+ICA1IGZpbGVzIGNoYW5nZWQsIDEw ODIgaW5zZXJ0aW9ucygrKSwgMSBkZWxldGlvbnMoLSkNCj4gDQo+IGRpZmYgLS1naXQgYS9NYWtl ZmlsZSBiL01ha2VmaWxlDQo+IGluZGV4IDI2ZDdkODIuLjJmN2Q5MjIgMTAwNjQ0DQo+IC0tLSBh L01ha2VmaWxlDQo+ICsrKyBiL01ha2VmaWxlDQpUaGlzIHNob3VsZG4ndCBiZSBpbiBhIGRyaXZl ciBwYXRjaC4NCj4gQEAgLTEsNyArMSw3IEBADQo+ICBWRVJTSU9OID0gMg0KPiAgUEFUQ0hMRVZF TCA9IDYNCj4gIFNVQkxFVkVMID0gMzgNCj4gLUVYVFJBVkVSU0lPTiA9IC1yYzYNCj4gK0VYVFJB VkVSU0lPTiA9IC1yYzcNCj4gIE5BTUUgPSBGbGVzaC1FYXRpbmcgQmF0cyB3aXRoIEZhbmdzDQo+ ICANCj4gICMgKkRPQ1VNRU5UQVRJT04qDQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3N0YWdpbmcv aWlvL0RvY3VtZW50YXRpb24vc3lzZnMtYnVzLWlpby1saWdodCANCj4gYi9kcml2ZXJzL3N0YWdp bmcvaWlvL0RvY3VtZW50YXRpb24vc3lzZnMtYnVzLWlpby1saWdodA0KPiBpbmRleCA1ZDg0ODU2 Li41YWZmYzJhIDEwMDY0NA0KPiAtLS0gYS9kcml2ZXJzL3N0YWdpbmcvaWlvL0RvY3VtZW50YXRp b24vc3lzZnMtYnVzLWlpby1saWdodA0KPiArKysgYi9kcml2ZXJzL3N0YWdpbmcvaWlvL0RvY3Vt ZW50YXRpb24vc3lzZnMtYnVzLWlpby1saWdodA0KPiBAQCAtNjIsMyArNjIsNjYgQEAgRGVzY3Jp cHRpb246DQo+ICAJCXNlbnNpbmcgbW9kZS4gVGhpcyB2YWx1ZSBzaG91bGQgYmUgdGhlIG91dHB1 dCBmcm9tIGEgcmVhZGluZw0KPiAgCQlhbmQgaWYgZXhwcmVzc2VkIGluIFNJIHVuaXRzLCBzaG91 bGQgaW5jbHVkZSBfaW5wdXQuIElmIHRoaXMNCj4gIAkJdmFsdWUgaXMgbm90IGluIFNJIHVuaXRz LCB0aGVuIGl0IHNob3VsZCBpbmNsdWRlIF9yYXcuDQo+ICsJCQ0KPiArV2hhdDoJCS9zeXMvYnVz L2lpby9kZXZpY2VzL2RldmljZVtuXS9kZXZpY2Vfc3RhdGUNCj4gK0tlcm5lbFZlcnNpb246CTIu Ni4zNw0KPiArQ29udGFjdDoJbGludXgtaWlvQHZnZXIua2VybmVsLm9yZw0KPiArRGVzY3JpcHRp b246DQo+ICsJCVRoaXMgcHJvcGVydHkgZ2V0cy9zZXRzIHRoZSBUQU9TIHRzbDI1OHggcG93ZXIg c3RhdGUuDQpUaGlzIGNlcnRhaW5seSBsb29rcyBtb3JlIGdlbmVyYWwgdGhhbiB0aGF0LiBJdCdz IG5vdCBsaWdodCBzZW5zb3Igc3BlY2lmaWMgc28gc2hvdWxkIGJlIGluIHN5c2ZzLWJ1cy1paW8g cmF0aGVyIHRoYW4gdGhlIGxpZ2h0IHJlbGF0ZWQgZG9jLiAgSGF2aW5nIHNhaWQgdGhhdCBpdCdz IGFsc28gYSByYXRoZXIgbm9uIHNwZWNpZmljIGRlc2NyaXB0aW9uIC8gbmFtZS4NCg0KSSd2ZSBi ZWVuIGdlbmVyYWxseSBwdXNoaW5nIGFnYWluc3QgaGF2aW5nIHRoaXMgc29ydCBvZiBwb3dlciBj b250cm9sIGFzIGFuIGV4cGxpY2l0IGF0dHJpYnV0ZSBpbiB0aGUgaWlvIGFiaSBzaW1wbHkgYmVj YXVzZSB0aGUgcmlnaHQgd2F5IHRvIGhhbmRsZSB0aGlzIGlzIHByb2JhYmx5IHJ1bnRpbWUgcG93 ZXIgbWFuYWdlbWVudC4gIFdlIGRpZCBsZXQgYSBmZXcgZHJpdmVycyBkbyB0aGlzIGVhcmx5IG9u IHNpbXBseSBiZWNhdXNlIHRoZXkgcHJlZGF0ZWQgcnVudGltZSBQTS4gIFRoYXQgZnJhbWV3b3Jr IGhhcyB0aGUgYWR2YW50YWdlIHRoYXQgaXQgYWxzbyBhbGxvd3MgZm9yIHRoZSBidXMgdG8gYmUg dHVybmVkIG9mZiBpZiBubyBkZXZpY2VzIG9uIGl0IG5lZWQgdG8gYmUgdGFsa2VkIHRvLiBJdCBt YXkgYmUgdGltZSB0byByZW9wZW4gdGhlIHByZXZpb3VzIGRpc2N1c3Npb24gb2YgaG93IHRvIGFs bG93IHVzZXJzcGFjZSB0byBleHBsaWNpdGx5IHNheSBpdCBkb2Vzbid0IGNhcmUgaWYgYSBkZXZp Y2UgaXMgcG93ZXJlZCB1cC4uLg0KDQpNT1ZFRCBUTyBTWVNGUy1CVVMtSUlPIERPQy4NCkNIQU5H RUQgVE8gUE9XRVJfU1RBVEUNCk5FRUQgQUJJTElUWSBGUk9NIFVTRVJTIFNQQUNFIFRPIFRVUk4g REVWSUNFIE9OL09GRiAoQUxMT1dTIFVTRVJTIFRPIENIQU5HRSBNVUxUSVBMRSBOT01JTkFMIE9Q UyBUSEVOIE9GRi9PTiB2cyBPRkYvT04gRk9SIEVBQ0ggQ0hBTkdFKQ0KUkVNT1ZFRCAiVEFPUyB0 c2wyNThYIiBGUk9NIEFMTCBET0NVTUVOVEFUSU9OIFJFRkVSRU5DRVMuDQoNCg0KPiArDQo+ICtX aGF0OgkJL3N5cy9idXMvaWlvL2RldmljZXMvZGV2aWNlW25dL2Fsc19nYWluDQo+ICtLZXJuZWxW ZXJzaW9uOgkyLjYuMzcNCj4gK0NvbnRhY3Q6CWxpbnV4LWlpb0B2Z2VyLmtlcm5lbC5vcmcNCj4g K0Rlc2NyaXB0aW9uOg0KPiArCQlUaGlzIHByb3BlcnR5IGdldHMvc2V0cyB0aGUgVEFPUyB0c2wy NTh4IGFuYWxvZyBnYWluIHNldHRpbmdzDQo+ICsJCW9mIHRoZSBkZXZpY2UuDQpBZ2FpbiwgcGxl YXNlIGdldCB0aGUgbWVudGlvbiBvZiBwYXJ0aWN1bGFyIHBhcnQgb3V0IG9mIHRoZSBkZXNjcmlw dGlvbi4NCkFsdGhvdWdoIGl0IGlzbid0IGV4cGxpY2l0bHkgc3BlY2lmaWVkICh5ZXQpIGZvciBs aWdodCBzZW5zb3JzLCB3ZSBkbyBoYXZlIGFuIGVxdWl2YWxlbnQgKEkgdGhpbmspIG9mIHRoaXMg YXNzdW1pbmcgaXQgaXMgYSBsaW5lYXIgcmVsYXRpb25zaGlwPw0KKGdvb2dsZSBmb3VuZCBtZSBh IGRhdGFzaGVldCBzbyBhdCBsZWFzdCBzdXBlcmZpY2lhbGx5IEkgdGhpbmsgaXQgaXMpLg0KVGhh dCBhdHRyaWJ1dGUgaXMgaWxsdW1pbmFuY2VfY2FsaWJzY2FsZSAoY2FsaWIgYml0IG1lYW5zIGl0 IGlzIGFwcGxpZWQgb24gZGV2aWNlIG9yIGluIGRyaXZlciByYXRoZXIgdGhhbiB0ZWxsaW5nIHVz ZXJzcGFjZSB3aGF0IG5lZWRzIHRvIGJlIGFwcGxpZWQgYnkgaXQpLiAoeWlrZXMsIGp1c3Qgbm90 aWNlZCB0aGF0IHRoaXMgaXMgd3JvbmcgaW4gdHNsMjU2MyB3aGVyZSB3ZSBoYXZlIGNhbGliZ2Fp biBkdWUgdG8gc29tZSBpbmNvbnNpc3RlbmN5IG9uIG15IHBhcnQgYSB3aGlsZSBiYWNrKS4NCg0K RE9ORSAtIENIQU5HRUQgTkFNRSBUTyBJTExVTUFOQ0VfQ0FMSUJTQ0FMRQ0KUkVNT1ZFRCBUSElT IFRFWFQgRlJPTSBET0MNCg0KQWxzbyBhdm9pZCAnbWFnaWMnIG51bWJlcnMgYXMgc2VlbiBoZXJl LiAgVGhlcmUgYXJlIGEgZmluaXRlIHJhbmdlIG9mIHBvc3NpYmxlIHZhbHVlcywgc28gaGF2ZSBh biBleHRyYSBhdHRyaWJ1dGVzIC0gaGVyZSBpbGx1bWluYW5jZV9jYWxpYnNjYWxlX2F2YWlsYWJs ZSB3aGljaCBpcyByZWFkIG9ubHkgYW5kIGdpdmVzIHRoZSBzdHJpbmcgIjEgOCAxNiAxMTEiIGFu ZCBtYWtlIGlsbHVtaW5hbmNlX2NhbGlic2NhbGUgcmV0dXJuIC1FSU5WQUwgaWYgdGhlIHZhbHVl IHdyaXR0ZW4gaXMgbm90IG9uZSBvZiB0aGVzZS4gc3lzZnNfc3RyZXEgaXMgcmVhbGx5IGhhbmR5 IGZvciB0aGlzIHNvcnQgb2YgbWF0Y2hpbmcuDQoNCk9rIC0gSE9XRVZFUiwgV0lUSCBSRVNQRUNU IFRPIFRISVM6IE9OTFkgQUxMT1dFRCBWQUxVRVMgQVJFIDAtMwkgKElOREVYIFJBVEhFUiBUSEFO IFNDQUxFIEZBQ1RPUiAgLSBTSU5DRSBXRSdSRSBVU0lORyBBIDIgUEFSVC9DSEFOTkVMIFNDQUxF KSANCkFEREVEIElMTFVNSU5BTkNFX0NBTElCU0NBTEVfQVZBSUxBQkxFDQoNCg0KPiArDQo+ICtX aGF0OgkJL3N5cy9idXMvaWlvL2RldmljZXMvZGV2aWNlW25dL2Fsc190aW1lDQo+ICtLZXJuZWxW ZXJzaW9uOgkyLjYuMzcNCj4gK0NvbnRhY3Q6CWxpbnV4LWlpb0B2Z2VyLmtlcm5lbC5vcmcNCj4g K0Rlc2NyaXB0aW9uOg0KPiArCQlUaGlzIHByb3BlcnR5IGdldHMvc2V0cyB0aGUgVEFPUyB0c2wy NTh4IEFEQyBjaGFubmVsIGludGVncmF0aW9uDQo+ICsJCXRpbWUgaW4gMi43bXMgaW5jcmVtZW50 cy4NCkFnYWluLCB0aGlzIGlzIG1vcmUgZ2VuZXJhbCB0aGFuIGp1c3Qgd29ya2luZyBmb3IgdGhl IHRzbDI1OHggZHJpdmVyLiBUaGF0IDIuN21zIGlzbid0IHRob3VnaC4gIFBsZWFzZSBtYWtlIHRo aXMgYSB2YWx1ZSBpbiBtaWxsaXNlY3MgKGZpeGVkIHBvaW50KSB0aGVuIGRlYWwgd2l0aCBjb252 ZXJzaW9uIHRvIHRoaXMgYmFzZSBpbiB0aGUgZHJpdmVyLiAgT24gdGhpcyBvbmUsIGl0IGlzIGNs b3NlbHkgcmVsYXRlZCB0byB0aGUgJ3BlcmlvZCcgYXR0cmlidXRlcyB0aGF0IGV4aXN0IGZvciB2 YXJpb3VzIGV2ZW50cy4gUGVyaGFwcyBpbGx1bWluYW5jZV9wZXJpb2QgaXMgYSBtb3JlIGNvbnNp c3RlbnQgbmFtZT8NCg0KQ0hBTkdFRCBUTyBTQU1QTElOR19GUkVRVUVOQ1kNClJFTU9WRUQgRk9S IExJR0hUIERPQyANCkFEREVEIFNBTVBMSU5HX0ZSRVFVRU5DWV9BVkFJTElBQkxFDQoNCj4gKw0K PiArV2hhdDoJCS9zeXMvYnVzL2lpby9kZXZpY2VzL2RldmljZVtuXS9hbHNfdHJpbQ0KPiArS2Vy bmVsVmVyc2lvbjoJMi42LjM3DQo+ICtDb250YWN0OglsaW51eC1paW9Admdlci5rZXJuZWwub3Jn DQo+ICtEZXNjcmlwdGlvbjoNCj4gKwkJVGhpcyBwcm9wZXJ0eSBnZXRzL3NldHMgdGhlIFRBT1Mg dHNsMjU4eCBBREMgYWN0aXZlIGdhaW4gc2NhbGUuDQpUaGlzIG9uZSBuZWVkcyBtb3JlIGRldGFp bCBiZWZvcmUgSSBjYW4gY29tbWVudC4gSSBjYW4ndCBmaWd1cmUgb3V0IHdoYXQgaXQgYWN0dWFs bHkgaXMhDQoNCkNIQU5HRUQgVE8gU0NBTEUNClJFTU9WRUQgRlJPTSBMSUdIVCBET0MNCg0KPiAr CQkNCj4gK1doYXQ6CQkvc3lzL2J1cy9paW8vZGV2aWNlcy9kZXZpY2Vbbl0vYWxzX3RhcmdldA0K PiArS2VybmVsVmVyc2lvbjoJMi42LjM3DQo+ICtDb250YWN0OglsaW51eC1paW9Admdlci5rZXJu ZWwub3JnDQo+ICtEZXNjcmlwdGlvbjoNCj4gKwkJVGhpcyBwcm9wZXJ0eSBnZXRzL3NldHMgdGhl IFRBT1MgdHNsMjU4eCBBREMgbGFzdCBrbm93biBleHRlcm5hbA0KPiArCQlsdXggbWVhc3VyZW1l bnQgdXNlZCBpbiBjYWxpYnJhdGlvbi4NCmFsc190YXJnZXQgLT4gaWxsdW1pbmFuY2UwX3Rhcmdl dA0KDQpDSEFOR0VEIFRPIElMTFVNSU5BTkNFMF9JTlBVVF9UQVJHRVQNCg0KbHV4IC0+IGlsbHVt aW5hbmNlLg0KV2hhdCB1bml0cz8NClNvdW5kcyBtb3JlIGdlbmVyYWwgdGhhbiB0aGUgdHNsMjU4 eCB0byBtZSBzbyBwZXJoYXBzIHNheSB0aGF0IGNoaXAgaXMgYW4gZXhhbXBsZSBvZiBpdHMgdXNl Pw0KPiArCQkNCj4gK1doYXQ6CQkvc3lzL2J1cy9paW8vZGV2aWNlcy9kZXZpY2Vbbl0vbHV4DQo+ ICtLZXJuZWxWZXJzaW9uOgkyLjYuMzcNCj4gK0NvbnRhY3Q6CWxpbnV4LWlpb0B2Z2VyLmtlcm5l bC5vcmcNCj4gK0Rlc2NyaXB0aW9uOg0KPiArCQlUaGlzIHByb3BlcnR5IGdldHMgdGhlIFRBT1Mg dHNsMjU4eCBjYWxjdWxhdGVkIGx1eCB2YWx1ZS4NClNvcnJ5LCBsdXggaXMgYSB1bml0LiBBdHRy aWJ1dGVzIGFyZSBuYW1lZCBhZnRlciB3aGF0IGlzIGJlaW5nIG1lYXN1cmVkLiAgSGVuY2UgaWxs dW1pbmFuY2UuICBNaWdodCBzZWVtIHJlYXNvbmFibGUgdG8gdXNlIHRoZSB1bml0LCBidXQgdGhl biB3aGF0IHdvdWxkIHdlIGRvIGZvciBhY2NlbGVyYXRpb24gKG0vc14yKT8gIEkgZ3Vlc3Mgd2Ug Y2FuIHJlb3BlbiB0aGlzIGRlYmF0ZSBhZ2FpbiBpZiB5b3UgYXJlIHJlYWxseSBhdHRhY2hlZCB0 byBsdXguLi4gIEFsc28gbmVlZHMgdG8gYmUgaWxsdW1pbmFuY2UwX2lucHV0LiAgVGhlIGlucHV0 IHNwZWNpZmljZXMgdGhhdCBpdCBpcyBpbiB0aGUgYmFzZSB1bml0IChsdXgpIHJhdGhlciB0aGFu IHJhdy4gV2Ugc3RpY2sgdG8gdGhpcyBmb3JtIHRvIG1haW50YWluIGNvbXBhdGlibGl0eSB3aXRo IGh3bW9uIHdoaWNoIGhhcyBiZWVuIGFyb3VuZCBhIGxvdCBsb25nZXIgdGhhbiB1cyENCg0KDQog Q0hBTkdFRCBUTyBJTExVTUlOQU5DRTBfVEFSR0VUDQoNCj4gKw0KPiArV2hhdDoJCS9zeXMvYnVz L2lpby9kZXZpY2VzL2RldmljZVtuXS9sdXhfdGFibGUNCj4gK0tlcm5lbFZlcnNpb246CTIuNi4z Nw0KPiArQ29udGFjdDoJbGludXgtaWlvQHZnZXIua2VybmVsLm9yZw0KPiArRGVzY3JpcHRpb246 DQo+ICsJCVRoaXMgcHJvcGVydHkgZ2V0cy9zZXRzIHRoZSBUQU9TIHRzbDI1OHggbHV4IHRhYmxl IG9mIGNvZWZmaWNpZW50cw0KPiArCQl0aGF0IGFyZSB1c2VkIHRvIGNhbGN1bGF0ZSBsdXguDQo+ ICsJCQ0KDQoNCj4gK1doYXQ6CQkvc3lzL2J1cy9paW8vZGV2aWNlcy9kZXZpY2Vbbl0vcmVnX29m ZnNldA0KPiArS2VybmVsVmVyc2lvbjoJMi42LjM3DQo+ICtDb250YWN0OglsaW51eC1paW9Admdl ci5rZXJuZWwub3JnDQo+ICtEZXNjcmlwdGlvbjoNCj4gKwkJVGhpcyBwcm9wZXJ0eSBnZXRzL3Nl dHMgYW4gaW5kZXggdGhlIFRBT1MgdHNsMjU4eCBpbnRlcm5lbCByZWdpc3Rlcg0KPiArCQlmb3Ig ci93IG9mIHNlbGVjdGVkIHJlZ2lzdGVyLg0KU29ycnksIG5vdCBsZXR0aW5nIGRpcmVjdCByZWdp c3RlciB3cml0ZSBhdHRyaWJ1dGVzIGluLiAgV2hhdCBkbyB5b3UgbmVlZCB0aGVzZSBmb3I/ICBD YW4gaXQgcmVhbGx5IG5vdCBiZSByZXBsYWNlZCBieSBtb3JlIGluZm9ybWF0aXZlIGF0dHJpYnV0 ZXM/DQo+ICsJCQ0KDQpSRU1PVkVEIFJFTU9WRUQgUkVHSVNURVIgUi9XIEFUVFJJQlVURSBGVU5D VElPTlMgIEZST00gRE9DICYgQ09ERQ0KDQo+ICtXaGF0OgkJL3N5cy9idXMvaWlvL2RldmljZXMv ZGV2aWNlW25dL3JlZ19vZmZzZXQNCj4gK0tlcm5lbFZlcnNpb246CTIuNi4zNw0KPiArQ29udGFj dDoJbGludXgtaWlvQHZnZXIua2VybmVsLm9yZw0KPiArRGVzY3JpcHRpb246DQo+ICsJCVRoaXMg cHJvcGVydHkgZ2V0cy9zZXRzIGFuIFRBT1MgdHNsMjU4eCBpbnRlcm5lbCByZWdpc3RlciB2YWx1 ZQ0KPiArCQlpbmRleGVkIGJ5IHJlZ19vZmZzZXQuDQo+ICsNCg0KUkVNT1ZFRCBBTEwgUkVHSVNU RVIgUkVBRCAvIFdSSVRFIEFUVFJJQlVURSBBQkkgRlVOQ1RJT05TDQoNCkV4dHJhIGVtcHR5IGxp bmVzLiBQbGVhc2UgcmVtb3ZlLiAgQWxzbyBwbGVhc2UgcnVuIGNoZWNrcGF0Y2ggb3ZlciB0aGlz IHBhdGNoLiBJIHRoaW5rIHRoZXJlIGFyZSBzb21lIGV4dHJhIHRhYnMgb24gdGhlc2UgbGluZXMg dGhhdCB3b24ndCBoYXZlIGdvdHRlbiB0aHJvdWdoIHRoYXQuDQo+ICsNCj4gKwkJDQo+IFwgTm8g bmV3bGluZSBhdCBlbmQgb2YgZmlsZQ0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9zdGFnaW5nL2lp by9saWdodC9LY29uZmlnIA0KPiBiL2RyaXZlcnMvc3RhZ2luZy9paW8vbGlnaHQvS2NvbmZpZw0K PiBpbmRleCAzNmQ4YmJlLi5hZTQ5OWI4IDEwMDY0NA0KPiAtLS0gYS9kcml2ZXJzL3N0YWdpbmcv aWlvL2xpZ2h0L0tjb25maWcNCj4gKysrIGIvZHJpdmVycy9zdGFnaW5nL2lpby9saWdodC9LY29u ZmlnDQo+IEBAIC0xMyw2ICsxMywxMyBAQCBjb25maWcgU0VOU09SU19UU0wyNTYzDQo+ICAJIFRo aXMgZHJpdmVyIGNhbiBhbHNvIGJlIGJ1aWx0IGFzIGEgbW9kdWxlLiAgSWYgc28sIHRoZSBtb2R1 bGUNCj4gIAkgd2lsbCBiZSBjYWxsZWQgdHNsMjU2My4NCj4gIA0KPiArY29uZmlnIFRBT1NfMjU4 eA0KPiArCXRyaXN0YXRlICJUQU9TIFRTTDI1OHggZGV2aWNlIGRyaXZlciINCj4gKwlkZWZhdWx0 IG0NCj4gKwloZWxwDQo+ICsJICBQcm92aWRlcyBzdXBwb3J0IGZvciB0aGUgVEFPUyB0c2wyNTh4 IGZhbWlseSBvZiBkZXZpY2VzLg0KPiArCSAgQWNjZXNzIEFMUyBkYXRhL2NvbnRyb2wgdmlhIHN5 c2ZzL2lpby4NClBsZWFzZSBsaXN0IGRldmljZXMuICBQZW9wbGUgdGVuZCB0byBncmVwIHRoZSB0 cmVlIGZvciB0aGUgcGFydCBudW1iZXIgb2YgdGhlIGRldmljZSB0aGF0IHRoZXkgYWN0dWFsbHkg aGF2ZSBoZW5jZSBpdCBpcyB1c2VmdWwgdG8gaGF2ZSB0aGVtIGFsbCBleHBsaWNpdGx5IGxpc3Rl ZCBoZXJlLiAgSW4gY29tYmluYXRpb24gd2l0aCB0aGUgaWQgdGFibGUgbGlzdGluZyB0aGVtIGFs bCB0aGlzIGFsc28gdGVuZHMgdG8gdGVsbCBwZW9wbGUgaWYgdGhlIGRldmVsb3BlciB0aGlua3Mg aXQgd2lsbCB3b3JrIHdpdGggdGhlIHBhcnQgdGhleSBoYXZlLg0KT0sgLSBDSEFOR0VEIFRPIHRz bDI1ODEgDQo+ICsNCj4gIGNvbmZpZyBTRU5TT1JTX0lTTDI5MDE4DQo+ICAgICAgICAgIHRyaXN0 YXRlICJJU0wgMjkwMTggbGlnaHQgYW5kIHByb3hpbWl0eSBzZW5zb3IiDQo+ICAgICAgICAgIGRl cGVuZHMgb24gSTJDDQo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3N0YWdpbmcvaWlvL2xpZ2h0L01h a2VmaWxlIA0KPiBiL2RyaXZlcnMvc3RhZ2luZy9paW8vbGlnaHQvTWFrZWZpbGUNCj4gaW5kZXgg OTE0MmMwZS4uNDM5NWRiOCAxMDA2NDQNCj4gLS0tIGEvZHJpdmVycy9zdGFnaW5nL2lpby9saWdo dC9NYWtlZmlsZQ0KPiArKysgYi9kcml2ZXJzL3N0YWdpbmcvaWlvL2xpZ2h0L01ha2VmaWxlDQo+ IEBAIC0zLDQgKzMsNSBAQA0KPiAgIw0KPiAgDQo+ICBvYmotJChDT05GSUdfU0VOU09SU19UU0wy NTYzKQkrPSB0c2wyNTYzLm8NCj4gK29iai0kKENPTkZJR19UQU9TXzI1OHgpCSs9IHRzbDI1OHgu bw0KPiAgb2JqLSQoQ09ORklHX1NFTlNPUlNfSVNMMjkwMTgpCSs9IGlzbDI5MDE4Lm8NCj4gZGlm ZiAtLWdpdCBhL2RyaXZlcnMvc3RhZ2luZy9paW8vbGlnaHQvdHNsMjU4eC5jIA0KPiBiL2RyaXZl cnMvc3RhZ2luZy9paW8vbGlnaHQvdHNsMjU4eC5jDQo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0DQo+ IGluZGV4IDAwMDAwMDAuLjIyNWQ4NWINCj4gLS0tIC9kZXYvbnVsbA0KPiArKysgYi9kcml2ZXJz L3N0YWdpbmcvaWlvL2xpZ2h0L3RzbDI1OHguYw0KPiBAQCAtMCwwICsxLDEwMTAgQEANCj4gKy8q DQo+ICsgKiBEZXZpY2UgZHJpdmVyIGZvciBtb25pdG9yaW5nIGFtYmllbnQgbGlnaHQgaW50ZW5z aXR5IChsdXgpDQo+ICsgKiB3aXRoaW4gdGhlIFRBT1MgdHNsMjU4eCBmYW1pbHkgb2YgZGV2aWNl cw0KPiArICoNCj4gKyAqIENvcHlyaWdodCAoYykgMjAxMSwgVEFPUyBDb3Jwb3JhdGlvbi4NCj4g KyAqDQo+ICsgKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3Ry aWJ1dGUgaXQgYW5kL29yIA0KPiArbW9kaWZ5DQo+ICsgKiBpdCB1bmRlciB0aGUgdGVybXMgb2Yg dGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCANCj4gK2J5DQo+ICsg KiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXIgdmVyc2lvbiAyIG9mIHRoZSBM aWNlbnNlLCBvcg0KPiArICogKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi4NCj4g KyAqDQo+ICsgKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBp dCB3aWxsIGJlIHVzZWZ1bCwgDQo+ICtidXQgV0lUSE9VVA0KPiArICogQU5ZIFdBUlJBTlRZOyB3 aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YgTUVSQ0hBTlRBQklMSVRZIA0KPiAr b3INCj4gKyAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUg R2VuZXJhbCBQdWJsaWMgDQo+ICtMaWNlbnNlIGZvcg0KPiArICogbW9yZSBkZXRhaWxzLg0KPiAr ICoNCj4gKyAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5l cmFsIFB1YmxpYyBMaWNlbnNlIA0KPiArYWxvbmcNCj4gKyAqIHdpdGggdGhpcyBwcm9ncmFtOyBp ZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIEluYy4sDQo+ICsg KiA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BCTAyMTEwLTEzMDEs IFVTQS4NCj4gKyAqLw0KPiArDQo+ICsjaW5jbHVkZSA8bGludXgva2VybmVsLmg+DQo+ICsjaW5j bHVkZSA8bGludXgvaTJjLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvZXJybm8uaD4NCj4gKyNpbmNs dWRlIDxsaW51eC9kZWxheS5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L3N0cmluZy5oPg0KPiArI2lu Y2x1ZGUgPGxpbnV4L211dGV4Lmg+DQo+ICsjaW5jbHVkZSAiLi4vaWlvLmgiDQo+ICsNCj4gKyNk ZWZpbmUgREVWSUNFX0lECQkJInRzbDI1OHgiDQo+ICsNCj4gKyNkZWZpbmUgTUFYX0RFVklDRV9S RUdTCQkzMg0KPiArDQpJJ20gZ3Vlc3NpbmcgdGhpcyBpcyBhbiBpbnRlcm5hbCBwYXJ0IG5hbWU/ ICBJZiBwb3NzaWJsZSBwbGVhc2UgcmVwbGFjZSB3aXRoIHRoZSBudW1iZXJzIHBlb3BsZSB3aWxs IHNlZSBvbiBkYXRhc2hlZXRzLg0KQ0hBTkdFRCBUTyBUU0wyNTgzDQoNCj4gKy8qIFRyaXRvbiBy ZWdpc3RlciBvZmZzZXRzICovDQo+ICsjZGVmaW5lCVRBT1NfUkVHX01BWAkJOA0KPiArDQo+ICsv KiBEZXZpY2UgUmVnaXN0ZXJzIGFuZCBNYXNrcyAqLw0KPiArI2RlZmluZSBUU0wyNThYX0NOVFJM CQkJMHgwMA0KVGhpcyBuZWVkcyBhIGEgY29tbWVudC4gIFdoeSB0d28gcmVncyB3aXRoIHRoZSBz YW1lIGFkZHJlc3M/IAktCURPTkUgIC0gUkVNT1ZFRCBTVEFUVVMNCj4gKyNkZWZpbmUgVFNMMjU4 WF9TVEFUVVMJCQkweDAwDQo+ICsjZGVmaW5lIFRTTDI1OFhfQUxTX1RJTUUJCTBYMDENCj4gKyNk ZWZpbmUgVFNMMjU4WF9JTlRFUlJVUFQJCTB4MDINCj4gKyNkZWZpbmUgVFNMMjU4WF9HQUlOCQkJ MHgwNw0KPiArI2RlZmluZSBUU0wyNThYX1JFVklECQkJMHgxMQ0KPiArI2RlZmluZSBUU0wyNThY X0NISVBJRAkJCTB4MTINCg0KQ3J5cHRpYyBuYW1lIGFuZCBuZXZlciB1c2VkLiBQbGVhc2UgcmVt b3ZlLgkJCS0JRE9ORSAtIFJFTU9WRUQNCj4gKyNkZWZpbmUgVFNMMjU4WF9TTUJfNAkJCTB4MTMN Cj4gKyNkZWZpbmUgVFNMMjU4WF9BTFNfQ0hBTjBMTwkJMHgxNA0KPiArI2RlZmluZSBUU0wyNThY X0FMU19DSEFOMEhJCQkweDE1DQo+ICsjZGVmaW5lIFRTTDI1OFhfQUxTX0NIQU4xTE8JCTB4MTYN Cj4gKyNkZWZpbmUgVFNMMjU4WF9BTFNfQ0hBTjFISQkJMHgxNw0KPiArI2RlZmluZSBUU0wyNThY X1RNUl9MTwkJCTB4MTgNCj4gKyNkZWZpbmUgVFNMMjU4WF9UTVJfSEkJCQkweDE5DQo+ICsNCj4g Ky8qIFNrYXRlIGNtZCByZWcgbWFza3MgKi8NCj4gKyNkZWZpbmUgVFNMMjU4WF9DTURfUkVHCQkw eDgwDQo+ICsjZGVmaW5lIFRTTDI1OFhfQ01EX0JZVEVfUlcJCTB4MDANCg0KVGhpcyBuYW1lIGNv bmZ1c2VzIG1lLiAgTG9va3MgbGlrZSBpdCBzZXRzIHdvcmQgcHJvdG9jb2wgc28gd2h5IHRoZSBi bG9jayBiaXQ/CS0gRE9ORSBSRU1PVkVEIEJMSw0KQWxzbyBub3QgdXNlZCBzbyBjb3VsZCBqdXN0 IGdldCByaWQgb2YgaXQuDQo+ICsjZGVmaW5lIFRTTDI1OFhfQ01EX1dPUkRfQkxLX1JXCTB4MjAN Cj4gKyNkZWZpbmUgVFNMMjU4WF9DTURfU1BMX0ZOCQkweDYwDQoNCk5pdHBpY2suIExhdGVyIHJl ZmVyZW5jZSB0byBJTlQgaGF2ZSBhbiBfIGFmdGVyIHRoZW0uIFBlcmhhcHMgYWRkIG9uZSBmb3Ig Y29uc2lzdGVuY3k/IC0gRE9ORQ0KDQo+ICsjZGVmaW5lIFRTTDI1OFhfQ01EX0FMU19JTlRDTFIJ CTBYMDENCj4gKw0KRXJyLiBTa2F0ZT8NCj4gKy8qIFNrYXRlIGNudHJsIHJlZyBtYXNrcyAqLw0K Tm90IHVzZWQgYW5kIHJhdGhlciBwb2ludGxlc3MuICBEZWZhdWx0IHdvdWxkIGJlIHRvIGFzc3Vt ZSB3cml0aW5nIDAgY2xlYXJlZCBhIHJlZ2lzdGVyPyAgKG9yIGRvZXMgdGhpcyBtZWFuIHNvbWV0 aGluZyBlbHNlPykJIC0gRE9ORQ0KDQo+ICsjZGVmaW5lIFRTTDI1OFhfQ05UTF9SRUdfQ0xFQVIJ CTB4MDANCj4gKyNkZWZpbmUgVFNMMjU4WF9DTlRMX0FMU19JTlRfRU5CTAkweDEwDQo+ICsjZGVm aW5lIFRTTDI1OFhfQ05UTF9XQUlUX1RNUl9FTkJMCTB4MDgNCj4gKyNkZWZpbmUgVFNMMjU4WF9D TlRMX0FEQ19FTkJMCQkweDAyDQo+ICsjZGVmaW5lIFRTTDI1OFhfQ05UTF9QV1JPTgkJMHgwMQ0K PiArI2RlZmluZSBUU0wyNThYX0NOVExfQUxTUE9OX0VOQkwJMHgwMw0KRGVmaW5lIHRoaXMgaW4g dGVybXMgb2YgUFdST04gYW5kIEFEQ19FTkJMIHRvIG1ha2UgaXQgY2xlYXIgd2hhdCBpdCBpcy4J LSBDSEFOR0VEIE5BTUUgUFdSX09OIChQT1dFUiBPTiBWUyBFTkFCTElORyBUSEUgQURDIEFSRSBE SUZGRVJFTlQpDQoNCj4gKyNkZWZpbmUgVFNMMjU4WF9DTlRMX0lOVEFMU1BPTl9FTkJMCTB4MTMJ CS0gUkVNT1ZFRA0KYWxzbyBkZWZpbmUgdGhpcyBpbiB0ZXJtcyBvZiBpdHMgc3ViIHBhcnRzLg0K PiArDQo+ICsvKiBTa2F0ZSBzdGF0dXMgcmVnIG1hc2tzICovDQo+ICsjZGVmaW5lIFRTTDI1OFhf U1RBX0FEQ1ZBTElECQkweDAxDQo+ICsjZGVmaW5lIFRTTDI1OFhfU1RBX0FMU0lOVFIJCTB4MTAN Cj4gKyNkZWZpbmUgVFNMMjU4WF9TVEFfQURDSU5UUgkJMHgxMA0KPiArDQo+ICsvKiBMdXggY29u c3RhbnRzICovDQo+ICsjZGVmaW5lCU1BWF9MVVgJCQk2NTUzNQkJLURPTkUgTkFNRSBDSEFOR0VE DQpFcnIuIFJlbmFtZSB0aGF0IHVubGVzcyBpdCByZWFsbHkgZG9lcyBtZWFuIDY1NTM1IGx1eA0K PiArDQo+ICtlbnVtIHsNCj4gKwlUQU9TX0NISVBfVU5LTk9XTiA9IDAsIFRBT1NfQ0hJUF9XT1JL SU5HID0gMSwgVEFPU19DSElQX1NMRUVQID0gMiB9IA0KPiArVEFPU19DSElQX1dPUktJTkdfU1RB VFVTOw0KPiArDQo+ICsvKiBQZXItZGV2aWNlIGRhdGEgKi8NCj4gK3N0cnVjdCB0YW9zX2Fsc19p bmZvIHsNCj4gKwl1MTYgYWxzX2NoMDsNCj4gKwl1MTYgYWxzX2NoMTsNCj4gKwl1MTYgbHV4Ow0K PiArfTsNCj4gKw0KPiArc3RydWN0IHRhb3Nfc2V0dGluZ3Mgew0KPiArCWludCBhbHNfdGltZTsN Cj4gKwlpbnQgYWxzX2dhaW47DQo+ICsJaW50IGFsc19nYWluX3RyaW07DQo+ICsJaW50IGFsc19j YWxfdGFyZ2V0Ow0KPiArfTsNCj4gKw0KPiArc3RydWN0IHRzbDI1OHhfY2hpcCB7DQo+ICsJc3Ry dWN0IG11dGV4IGFsc19tdXRleDsNCj4gKwlzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50Ow0KPiAr CXN0cnVjdCBpaW9fZGV2ICppaW9fZGV2Ow0KPiArCXN0cnVjdCBkZWxheWVkX3dvcmsgdXBkYXRl X2x1eDsNCj4gKwl1bnNpZ25lZCBpbnQgYWRkcjsNCj4gKwljaGFyIHRhb3NfaWQ7DQo+ICsJY2hh ciB2YWxpZDsNCj4gKwl1bnNpZ25lZCBsb25nIGxhc3RfdXBkYXRlZDsNCj4gKwlzdHJ1Y3QgdGFv c19hbHNfaW5mbyBhbHNfY3VyX2luZm87DQo+ICsJc3RydWN0IHRhb3Nfc2V0dGluZ3MgdGFvc19z ZXR0aW5nczsNCj4gKwlpbnQgYWxzX3RpbWVfc2NhbGU7DQo+ICsJaW50IGFsc19zYXR1cmF0aW9u Ow0KPiArCWludCB0YW9zX2NoaXBfc3RhdHVzOw0KPiArCXU4IHRhb3NfY29uZmlnWzhdOw0KPiAr fTsNCj4gKw0KPiArc3RhdGljIGludCB0YW9zX2kyY19yZWFkKHN0cnVjdCBpMmNfY2xpZW50ICpj bGllbnQsIHU4IHJlZywgdTggKnZhbCwNCj4gKwl1bnNpZ25lZCBpbnQgbGVuKTsNCj4gK3N0YXRp YyBpbnQgdGFvc19pMmNfd3JpdGVfY29tbWFuZChzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LCB1 OCByZWcpOw0KPiArDQo+ICsvKg0KPiArICogSW5pdGlhbCB2YWx1ZXMgZm9yIGRldmljZSAtIHRo aXMgdmFsdWVzIGNhbi93aWxsIGJlIGNoYW5nZWQgYnkgZHJpdmVyLg0KPiArICogYW5kIGFwcGxp Y2F0aW9ucyBhcyBuZWVkZWQuDQo+ICsgKiBUaGVzZSB2YWx1ZXMgYXJlIGR5bmFtaWMuDQo+ICsg Ki8NCj4gK3N0YXRpYyBjb25zdCB1OCB0YW9zX2NvbmZpZ1s4XSA9IHsNCj4gKwkJMHgwMCwgMHhl ZSwgMHgwMCwgMHgwMywgMHgwMCwgMHhGRiwgMHhGRiwgMHgwMA0KPiArfTsgLyoJY250cmwgYXRp bWUgaW50QyAgQXRobDAgQXRobDEgQXRoaDAgQXRoaDEgZ2FpbiAqLw0KPiArDQo+ICtzdHJ1Y3Qg dGFvc19sdXggew0KPiArCXVuc2lnbmVkIGludCByYXRpbzsNCj4gKwl1bnNpZ25lZCBpbnQgY2gw Ow0KPiArCXVuc2lnbmVkIGludCBjaDE7DQo+ICt9Ow0KPiArDQo+ICsvKiBUaGlzIHN0cnVjdHVy ZSBpcyBpbnRlbnRpb25hbGx5IGxhcmdlIHRvIGFjY29tbW9kYXRlIHVwZGF0ZXMgdmlhIA0KPiAr c3lzZnMuICovDQo+ICsvKiBTaXplZCB0byAxMSA9IG1heCAxMCBzZWdtZW50cyArIDEgdGVybWlu YXRpb24gc2VnbWVudCAqLw0KQW55IGNoYW5jZSBvZiB0d28gc2Vuc29ycyBvbiBvbmUgZGV2aWNl LCBlYWNoIG9mIHdoaWNoIGhhcyBkaWZmZXJlbnQgdmFsdWVzIGZvciB0aGlzPwktICBOTyAsIExV WCBUQUJMRSBJUyBGT1IgR0xBU1MgTk9UIERFVklDRQ0KDQo+ICtzdHJ1Y3QgdGFvc19sdXggdGFv c19kZXZpY2VfbHV4WzExXSA9IHsNCj4gKwl7ICA5ODMwLCAgODUyMCwgMTU3MjkgfSwNCj4gKwl7 IDEyNDUyLCAxMDgwNywgMjMzNDQgfSwNCj4gKwl7IDE0NzQ2LCAgNjM4MywgMTE3MDUgfSwNCj4g Kwl7IDE3Njk1LCAgNDA2MywgIDY1NTQgfSwNCj4gK307DQo+ICsNCj4gK3N0cnVjdCB0YW9zX2x1 eCB0YW9zX2x1eDsNCj4gKw0KPiArc3RydWN0IGdhaW5hZGogew0KPiArCXMxNiBjaDA7DQo+ICsJ czE2IGNoMTsNCj4gK307DQo+ICsNCj4gKy8qIEluZGV4ID0gKDAgLSAzKSBVc2VkIHRvIHZhbGlk YXRlIHRoZSBnYWluIHNlbGVjdGlvbiBpbmRleCAqLyANCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3Qg Z2FpbmFkaiBnYWluYWRqW10gPSB7DQo+ICsJeyAxLCAxIH0sDQo+ICsJeyA4LCA4IH0sDQo+ICsJ eyAxNiwgMTYgfSwNClRoYXQncyAnaW50ZXJlc3RpbmcnLiAgVGhpcyB3aWxsIG1ha2UgdGhlIGNh bGlic2NhbGUgZGlzY3Vzc2lvbiBhYm92ZSBtb3JlIGNvbXBsZXguICBJIGd1ZXNzIG5vIHVzZXJz cGFjZSBpcyBnb2luZyB0byBjYXJlIGFib3V0IHRoZSBwcmVjaXNlIGludGVybmFsIG11bHRpcGxp ZXJzIHNvIGEgJ3JvdWdoJyB2YWx1ZSB3b3VsZCBwcm9iYWJseSBkbyBpbiB0aGF0IGF0dHJpYnV0 ZS4gV2hhdCBkbyB5b3UgdGhpbms/DQpUSElTIEFDQ09NTU9EQVRFUyBBIERJRkZFUkVOVElBTCBD SEFSQUNURVJJU1RJQyAoSU4gVEhJUyBGQU1JTFkgT0YgREVWSUNFKSAgQkVUV0VFTiBBREMgQ0hB Tk5FTFMgQVQgSElHSEVSIEdBSU4uICBUSElTIElTIEFOIElOVEVSTkFML0RSSVZFUiBDQUxDVUxB VElPTi4gIFVTRVJTUEFDRSBTSU1QTFkgU0VMRUNUUyBHQUlOIElOREVYIDAgLSAzLiAgDQo+ICsJ eyAxMDcsIDExNSB9DQo+ICt9Ow0KPiArDQo+ICsvKg0KPiArICogUHJvdmlkZXMgaW5pdGlhbCBv cGVyYXRpb25hbCBwYXJhbWV0ZXIgZGVmYXVsdHMuDQo+ICsgKiBUaGVzZSBkZWZhdWx0cyBtYXkg YmUgY2hhbmdlZCB0aHJvdWdoIHRoZSBkZXZpY2UncyBzeXNmcyBmaWxlcy4NCj4gKyAqLw0KPiAr c3RhdGljIHZvaWQgdGFvc19kZWZhdWx0cyhzdHJ1Y3QgdHNsMjU4eF9jaGlwICpjaGlwKSB7DQo+ ICsJLyogT3BlcmF0aW9uYWwgcGFyYW1ldGVycyAqLw0KPiArCWNoaXAtPnRhb3Nfc2V0dGluZ3Mu YWxzX3RpbWUgPSA0NTA7DQo+ICsJLyogbXVzdCBiZSBhIG11bHRpcGxlIG9mIDUwbVMgKi8NCj4g KwljaGlwLT50YW9zX3NldHRpbmdzLmFsc19nYWluID0gMjsNCj4gKwkvKiB0aGlzIGlzIGFjdHVh bGx5IGFuIGluZGV4IGludG8gdGhlIGdhaW4gdGFibGUgKi8NCj4gKwkvKiBhc3N1bWUgY2xlYXIg Z2xhc3MgYXMgZGVmYXVsdCAqLw0KPiArCWNoaXAtPnRhb3Nfc2V0dGluZ3MuYWxzX2dhaW5fdHJp bSA9IDEwMDA7DQo+ICsJLyogZGVmYXVsdCBnYWluIHRyaW0gdG8gYWNjb3VudCBmb3IgYXBlcnR1 cmUgZWZmZWN0cyAqLw0KPiArCWNoaXAtPnRhb3Nfc2V0dGluZ3MuYWxzX2NhbF90YXJnZXQgPSAx MzA7DQo+ICsJLyogS25vd24gZXh0ZXJuYWwgQUxTIHJlYWRpbmcgdXNlZCBmb3IgY2FsaWJyYXRp b24gKi8NCj4gKw0KPiArCS8qIEluaXRpYWxpemUgQUxTIGRhdGEgdG8gZGVmYXVsdHMgKi8NCj4g KwljaGlwLT5hbHNfY3VyX2luZm8uYWxzX2NoMCA9IDA7DQo+ICsJY2hpcC0+YWxzX2N1cl9pbmZv LmFsc19jaDEgPSAwOw0KPiArCWNoaXAtPmFsc19jdXJfaW5mby5sdXggPSAwOw0KQWxyZWFkeSB6 ZXJvIHZpYSB0aGUgbWVtc2V0IChzb29uIHRvIGJlIGt6YWxsb2MpIGhlbmNlIGRvbid0IGJvdGhl ciBzZXR0aW5nIHRoZXNlIHRocmVlLgktIERPTkUNCj4gK30NCj4gKw0KPiArLyoNCj4gKyAqIFJl YWQgYSBudW1iZXIgb2YgYnl0ZXMgc3RhcnRpbmcgYXQgcmVnaXN0ZXIgKHJlZykgbG9jYXRpb24u DQo+ICsgKiBSZXR1cm4gMCwgb3IgaTJjX3NtYnVzX3dyaXRlX2J5dGUgRVJST1IgY29kZS4NCj4g KyAqLw0KPiArc3RhdGljIGludA0KPiArdGFvc19pMmNfcmVhZChzdHJ1Y3QgaTJjX2NsaWVudCAq Y2xpZW50LCB1OCByZWcsIHU4ICp2YWwsIHVuc2lnbmVkIA0KPiAraW50IGxlbikgew0KPiArCWlu dCByZXQ7DQo+ICsJaW50IGk7DQo+ICsNCj4gKwlmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHsN Cj4gKwkJLyogc2VsZWN0IHJlZ2lzdGVyIHRvIHdyaXRlICovDQo+ICsJCXJldCA9IGkyY19zbWJ1 c193cml0ZV9ieXRlKGNsaWVudCwgKFRTTDI1OFhfQ01EX1JFRyB8IHJlZykpOw0KPiArCQlpZiAo cmV0IDwgMCkgew0KPiArCQkJZGV2X2VycigmY2xpZW50LT5kZXYsICJ0YW9zX2kyY19yZWFkIGZh aWxlZCB0byB3cml0ZSINCj4gKwkJCQkiIHJlZ2lzdGVyICV4XG4iLCByZWcpOw0KPiArCQkJcmV0 dXJuIHJldDsNCj4gKwkJfQ0KPiArCQkvKiByZWFkIHRoZSBkYXRhICovDQo+ICsJCSp2YWwgPSBp MmNfc21idXNfcmVhZF9ieXRlKGNsaWVudCk7DQpJJ2QgdXNlIHZhbFtpXSB3aXRob3V0IHRoaXMg aW5jcmVtZW50IGZvciBjbGFyaXR5Lg0KPiArCQl2YWwrKzsNCj4gKwkJaWYgKChyZWcgJiAweDFm KSA9PSAweDFmKQ0KQ2FuIHRoaXMgZXZlciBvY2NjdXIgaW4gdGhlIGRyaXZlcj8gIEkgd291bGQg aW1hZ2luZSBpdCBpcyBhIGJ1ZyBpZiBpdCBkb2VzIGFzIHlvdSdsbCByZWFkIGJhY2sgYSBkaWZm ZXJlbnQgbnVtYmVyIG9mIHZhbHVlcyB0aGFuIHlvdSBleHBlY3QgdG8gZG8uCS0gRE9ORSBSRU1P VkVEDQpJZiBub3QgaXQncyBhbiBvdmVyIGVudGh1c2lhc3RpYyBiaXQgb2YgZGVidWcgY29kZSBz byBnZXQgcmlkIG9mIGl0Lg0KPiArCQkJYnJlYWs7DQo+ICsJCXJlZysrOw0KPiArCX0NCj4gKwly ZXR1cm4gMDsNCj4gK30NCj4gKw0KPiArLyoNCj4gKyAqIFRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0 byBzZW5kIGEgY29tbWFuZCB0byBkZXZpY2UgY29tbWFuZC9jb250cm9sIA0KPiArcmVnaXN0ZXIN Cj4gKyAqIEFsbCBieXRlcyBzZW50IHVzaW5nIHRoaXMgY29tbWFuZCBoYXZlIHRoZWlyIE1TQml0 IHNldCAtIGl0J3MgYSBjb21tYW5kIQ0KPiArICogUmV0dXJuIDAsIG9yIGkyY19zbWJ1c193cml0 ZV9ieXRlIGVycm9yIGNvZGUuDQo+ICsgKi8NCj4gK3N0YXRpYyBpbnQgdGFvc19pMmNfd3JpdGVf Y29tbWFuZChzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LCB1OCByZWcpIA0KPiArew0KPiArCWlu dCByZXQ7DQo+ICsNCj4gKwkvKiB3cml0ZSB0aGUgZGF0YSAqLw0KPiArCXJldCA9IGkyY19zbWJ1 c193cml0ZV9ieXRlKGNsaWVudCwgKHJlZyB8PSBUU0wyNThYX0NNRF9SRUcpKTsNCj4gKwlpZiAo cmV0IDwgMCkgew0KPiArCQlkZXZfZXJyKCZjbGllbnQtPmRldiwgIkZBSUxFRDogaTJjX3NtYnVz X3dyaXRlX2J5dGVcbiIpOw0KPiArCQlyZXR1cm4gcmV0Ow0KPiArCX0NCj4gKwlyZXR1cm4gMDsN Cj4gK30NCj4gKw0KPiArLyoNCj4gKyAqIFJlYWRzIGFuZCBjYWxjdWxhdGVzIGN1cnJlbnQgbHV4 IHZhbHVlLg0KPiArICogVGhlIHJhdyBjaDAgYW5kIGNoMSB2YWx1ZXMgb2YgdGhlIGFtYmllbnQg bGlnaHQgc2Vuc2VkIGluIHRoZSBsYXN0DQo+ICsgKiBpbnRlZ3JhdGlvbiBjeWNsZSBhcmUgcmVh ZCBmcm9tIHRoZSBkZXZpY2UuDQo+ICsgKiBUaW1lIHNjYWxlIGZhY3RvciBhcnJheSB2YWx1ZXMg YXJlIGFkanVzdGVkIGJhc2VkIG9uIHRoZSBpbnRlZ3JhdGlvbiB0aW1lLg0KPiArICogVGhlIHJh dyB2YWx1ZXMgYXJlIG11bHRpcGxpZWQgYnkgYSBzY2FsZSBmYWN0b3IsIGFuZCBkZXZpY2UgZ2Fp biANCj4gK2lzIG9idGFpbmVkDQo+ICsgKiB1c2luZyBnYWluIGluZGV4LiBMaW1pdCBjaGVja3Mg YXJlIGRvbmUgbmV4dCwgdGhlbiB0aGUgcmF0aW8gb2YgYSANCj4gK211bHRpcGxlDQo+ICsgKiBv ZiBjaDEgdmFsdWUsIHRvIHRoZSBjaDAgdmFsdWUsIGlzIGNhbGN1bGF0ZWQuIFRoZSBhcnJheSAN Cj4gK3Rhb3NfZGV2aWNlX2x1eFtdDQo+ICsgKiBkZWNsYXJlZCBhYm92ZSBpcyB0aGVuIHNjYW5u ZWQgdG8gZmluZCB0aGUgZmlyc3QgcmF0aW8gdmFsdWUgdGhhdCANCj4gK2lzIGp1c3QNCj4gKyAq IGFib3ZlIHRoZSByYXRpbyB3ZSBqdXN0IGNhbGN1bGF0ZWQuIFRoZSBjaDAgYW5kIGNoMSBtdWx0 aXBsaWVyIA0KPiArY29uc3RhbnRzIGluDQo+ICsgKiB0aGUgYXJyYXkgYXJlIHRoZW4gdXNlZCBh bG9uZyB3aXRoIHRoZSB0aW1lIHNjYWxlIGZhY3RvciBhcnJheSANCj4gK3ZhbHVlcywgdG8NCj4g KyAqIGNhbGN1bGF0ZSB0aGUgbHV4Lg0KPiArICovDQo+ICtzdGF0aWMgaW50IHRhb3NfZ2V0X2x1 eChzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50KSB7DQo+ICsJdTMyIGNoMCwgY2gxOyAvKiBzZXBh cmF0ZWQgY2gwL2NoMSBkYXRhIGZyb20gZGV2aWNlICovDQo+ICsJdTMyIGx1eDsgLyogcmF3IGx1 eCBjYWxjdWxhdGVkIGZyb20gZGV2aWNlIGRhdGEgKi8NCkFuZCBoZXJlIHdlIGhhdmUgYSBncmVh dCBleGFtcGxlIG9mIHdoeSBsdXggaXMgYSBiYWQgbmFtZSBmb3IgdGhpcy4NCmx1eCBjb3VsZCBv bmx5IGV2ZXIgaGF2ZSB1bml0cyBvZiBsdXguCQkJCQlPSyAtIEdPVCBZT1VSIFBPSU5UIA0KPiAr CXUzMiByYXRpbzsNCj4gKwl1OCBidWZbNV07DQo+ICsJc3RydWN0IHRhb3NfbHV4ICpwOw0KPiAr CXN0cnVjdCB0c2wyNTh4X2NoaXAgKmNoaXAgPSBpMmNfZ2V0X2NsaWVudGRhdGEoY2xpZW50KTsN Cj4gKwlpbnQgaSwgcmV0Ow0KPiArCXUzMiBjaDBsdXggPSAwOw0KPiArCXUzMiBjaDFsdXggPSAw Ow0KPiArDQo+ICsJaWYgKG11dGV4X3RyeWxvY2soJmNoaXAtPmFsc19tdXRleCkgPT0gMCkgew0K PiArCQlkZXZfaW5mbygmY2xpZW50LT5kZXYsICJ0YW9zX2dldF9sdXggZGV2aWNlIGlzIGJ1c3lc biIpOw0KPiArCQlyZXR1cm4gY2hpcC0+YWxzX2N1cl9pbmZvLmx1eDsgLyogYnVzeSwgc28gcmV0 dXJuIExBU1QgVkFMVUUgKi8NCj4gKwl9DQo+ICsNCj4gKwlpZiAoY2hpcC0+dGFvc19jaGlwX3N0 YXR1cyAhPSBUQU9TX0NISVBfV09SS0lORykgew0KPiArCQkvKiBkZXZpY2UgaXMgbm90IGVuYWJs ZWQgKi8NCj4gKwkJZGV2X2VycigmY2xpZW50LT5kZXYsICJ0YW9zX2dldF9sdXggZGV2aWNlIGlz IG5vdCBlbmFibGVkXG4iKTsNCj4gKwkJcmV0ID0gLUVOT0RFVjsNCi1FQlVTWSBwcm9iYWJseS4g VGhlIGRldmljZSBleGlzdHMsIGl0J3MganVzdCB0dXJuZWQgb2ZmLgkJCQktIERPTkUgQ0hBTkdF RA0KDQo+ICsJCWdvdG8gb3V0X3VubG9jazsNCj4gKwl9DQo+ICsNCj4gKwlyZXQgPSB0YW9zX2ky Y19yZWFkKGNsaWVudCwgKFRTTDI1OFhfQ01EX1JFRyksICZidWZbMF0sIDEpOw0KPiArCWlmIChy ZXQgPCAwKSB7DQo+ICsJCWRldl9lcnIoJmNsaWVudC0+ZGV2LCAidGFvc19nZXRfbHV4IGZhaWxl ZCB0byByZWFkIENNRF9SRUdcbiIpOw0KPiArCQlnb3RvIG91dF91bmxvY2s7DQo+ICsJfQ0KPiAr CS8qIGlzIGRhdGEgbmV3ICYgdmFsaWQgKi8NCj4gKwlpZiAoIShidWZbMF0gJiBUU0wyNThYX1NU QV9BRENJTlRSKSkgew0KPiArCQlkZXZfZXJyKCZjbGllbnQtPmRldiwgInRhb3NfZ2V0X2x1eCBk YXRhIG5vdCB2YWxpZFxuIik7DQogIEknZCBlcnJvciBvdXQgYXQgdGhpcyBwb2ludC4gU29tZXRo aW5nIGhhcyBnb25lIHdyb25nIGFuZCB5b3Ugd2FudCB0byBpbmRpY2F0ZSBpdCB0byB5b3VyIHVz ZXJzcGFjZSBjb2RlLgkJLSBOTzogQURDIE1BWSBKVVNUIE5PVCBIQVZFIEZJTklTSEVELiAgSUYg VVNFUlNQQUNFIElTIFBPTExJTkcgQkVUVEVSIFRPIFBBU1MgQkFDSyBQUkVWSU9VUyBWQUxVRSBU SEFOIFRPIEVSUk9SDQoJCQkJCQkJCQkJCQkJCS0gQkFTRUQgT04gQ1VTVE9NRVIgRkVFREJBQ0sN Cj4gKwkJcmV0ID0gY2hpcC0+YWxzX2N1cl9pbmZvLmx1eDsgLyogcmV0dXJuIExBU1QgVkFMVUUg Ki8NCj4gKwkJZ290byBvdXRfdW5sb2NrOw0KPiArCX0NCj4gKw0KPiArCWZvciAoaSA9IDA7IGkg PCA0OyBpKyspIHsNCj4gKwkJaW50IHJlZyA9IFRTTDI1OFhfQ01EX1JFRyB8IChUU0wyNThYX0FM U19DSEFOMExPICsgaSk7DQo+ICsJCXJldCA9IHRhb3NfaTJjX3JlYWQoY2xpZW50LCByZWcsICZi dWZbaV0sIDEpOw0KPiArCQlpZiAocmV0IDwgMCkgew0KPiArCQkJZGV2X2VycigmY2xpZW50LT5k ZXYsICJ0YW9zX2dldF9sdXggZmFpbGVkIHRvIHJlYWQiDQo+ICsJCQkJIiByZWdpc3RlciAleFxu IiwgcmVnKTsNCj4gKwkJCWdvdG8gb3V0X3VubG9jazsNCj4gKwkJfQ0KPiArCX0NCj4gKw0KPiAr CS8qIGNsZWFyIHN0YXR1cywgcmVhbGx5IGludGVycnVwdCBzdGF0dXMgKGludGVycnVwdHMgYXJl IG9mZiksIGJ1dA0KPiArCSAqIHdlIHVzZSB0aGUgYml0IGFueXdheSAqLw0KPiArCXJldCA9IHRh b3NfaTJjX3dyaXRlX2NvbW1hbmQoY2xpZW50LA0KPiArCQlUU0wyNThYX0NNRF9SRUcgfCBUU0wy NThYX0NNRF9TUExfRk4gfCBUU0wyNThYX0NNRF9BTFNfSU5UQ0xSKTsNCj4gKwlpZiAocmV0IDwg MCkgew0KPiArCQlkZXZfZXJyKCZjbGllbnQtPmRldiwNCiBUaGlzIGlzIHRoZSBvbmUgY2FzZSB3 aGVyZSBjaGVja3BhdGNoIHdhcm5pbmdzIHNob3VsZCBiZSBpZ25vcmVkLg0KUGxlYXNlIGtlZXAg c3RyaW5ncyBsaWtlIHRoaXMgb24gYSBzaW5nbGUgbGluZSBhcyBwZW9wbGUgd2hvIHNlZSB0aGVt IGluIGEgbG9nIHdpbGwgZ3JlcCBmb3IgdGhlbSBpbiB0aGUgc291cmNlIGNvZGUuICBBcnRpZmlj aWFsIGJyZWFrcyBsaWtlIHRoaXMgbWFrZSB0aGVtIGEgbG90IGhhcmRlciB0byBmaW5kISAtIERP TkUNCg0KPiArCQkidGFvc19pMmNfd3JpdGVfY29tbWFuZCBmYWlsZWQgaW4gIg0KPiArCQkidGFv c19nZXRfbHV4LCBlcnIgPSAlZFxuIiwgcmV0KTsNCj4gKwkJZ290byBvdXRfdW5sb2NrOyAvKiBo YXZlIG5vIGRhdGEsIHNvIHJldHVybiBmYWlsdXJlICovDQo+ICsJfQ0KPiArDQo+ICsJLyogZXh0 cmFjdCBBTFMvbHV4IGRhdGEgKi8NClNob3VsZCBiZSB0aGUgcmVsZXZhbnQgZW5kaWFuIGNvbnZl cnNpb24gZnVuY3Rpb24uICBiZTE2dG9jcHUgb3Igc2ltaWxhciAoaGF2ZW4ndCB0aG91Z2h0IGFi b3V0IHdoaWNoKS4gIFRoYXQgd2F5IGl0J3MgZnJlZSBvbiBvbmUgZW5kaWFubmVzcyBvZiBtYWNo aW5lLg0KPiArCWNoMCA9IChidWZbMV0gPDwgOCkgfCBidWZbMF07DQo+ICsJY2gxID0gKGJ1Zlsz XSA8PCA4KSB8IGJ1ZlsyXTsNCj4gKw0KPiArCWNoaXAtPmFsc19jdXJfaW5mby5hbHNfY2gwID0g Y2gwOw0KPiArCWNoaXAtPmFsc19jdXJfaW5mby5hbHNfY2gxID0gY2gxOw0KPiArDQo+ICsJaWYg KChjaDAgPj0gY2hpcC0+YWxzX3NhdHVyYXRpb24pIHx8IChjaDEgPj0gY2hpcC0+YWxzX3NhdHVy YXRpb24pKQ0KPiArCQlnb3RvIHJldHVybl9tYXg7DQo+ICsNCj4gKwlpZiAoY2gwID09IDApIHsN Cj4gKwkJLyogaGF2ZSBubyBkYXRhLCBzbyByZXR1cm4gTEFTVCBWQUxVRSAqLw0KPiArCQlyZXQg PSBjaGlwLT5hbHNfY3VyX2luZm8ubHV4ID0gMDsNCj4gKwkJZ290byBvdXRfdW5sb2NrOw0KPiAr CX0NCj4gKwkvKiBjYWxjdWxhdGUgcmF0aW8gKi8NCj4gKwlyYXRpbyA9IChjaDEgPDwgMTUpIC8g Y2gwOw0KPiArCS8qIGNvbnZlcnQgdG8gdW5zY2FsZWQgbHV4IHVzaW5nIHRoZSBwb2ludGVyIHRv IHRoZSB0YWJsZSAqLw0KPiArCWZvciAocCA9IChzdHJ1Y3QgdGFvc19sdXggKikgdGFvc19kZXZp Y2VfbHV4Ow0KPiArCSAgICAgcC0+cmF0aW8gIT0gMCAmJiBwLT5yYXRpbyA8IHJhdGlvOyBwKysp DQo+ICsJCTsNCj4gKw0KPiArCWlmIChwLT5yYXRpbyA9PSAwKSB7DQo+ICsJCWx1eCA9IDA7DQo+ ICsJfSBlbHNlIHsNCj4gKwkJY2gwbHV4ID0gKChjaDAgKiBwLT5jaDApICsNCj4gKwkJCSAgKGdh aW5hZGpbY2hpcC0+dGFvc19zZXR0aW5ncy5hbHNfZ2Fpbl0uY2gwID4+IDEpKQ0KPiArCQkJIC8g Z2FpbmFkaltjaGlwLT50YW9zX3NldHRpbmdzLmFsc19nYWluXS5jaDA7DQo+ICsJCWNoMWx1eCA9 ICgoY2gxICogcC0+Y2gxKSArDQo+ICsJCQkgIChnYWluYWRqW2NoaXAtPnRhb3Nfc2V0dGluZ3Mu YWxzX2dhaW5dLmNoMSA+PiAxKSkNCj4gKwkJCSAvIGdhaW5hZGpbY2hpcC0+dGFvc19zZXR0aW5n cy5hbHNfZ2Fpbl0uY2gxOw0KPiArCQlsdXggPSBjaDBsdXggLSBjaDFsdXg7DQo+ICsJfQ0KPiAr DQo+ICsJLyogbm90ZTogbHV4IGlzIDMxIGJpdCBtYXggYXQgdGhpcyBwb2ludCAqLw0KPiArCWlm IChjaDFsdXggPiBjaDBsdXgpIHsNCj4gKwkJZGV2X2RiZygmY2xpZW50LT5kZXYsICJObyBEYXRh IC0gUmV0dXJuIGxhc3QgdmFsdWVcbiIpOw0KQWdhaW4sIGRvIHdlIHdhbnQgdXNlcnNwYWNlIHRv IGtub3cgdGhlIHNlbnNvciBpc24ndCByZXR1cm5pbmcgdmFsaWQgdmFsdWVzPwktIE5PIC0gTk9U IE5FQ0VTU0FSTFkgLSBKVVNUIE1FQU5TIENIMSAoSVIpIFdFTlQgSElHSEVSIFRIQU4gQ0gwIChW SVNBQkxFKSANCj4gKwkJcmV0ID0gY2hpcC0+YWxzX2N1cl9pbmZvLmx1eCA9IDA7DQo+ICsJCWdv dG8gb3V0X3VubG9jazsNCj4gKwl9DQo+ICsNCj4gKwkvKiBhZGp1c3QgZm9yIGFjdGl2ZSB0aW1l IHNjYWxlICovDQo+ICsJaWYgKGNoaXAtPmFsc190aW1lX3NjYWxlID09IDApDQo+ICsJCWx1eCA9 IDA7DQo+ICsJZWxzZQ0KPiArCQlsdXggPSAobHV4ICsgKGNoaXAtPmFsc190aW1lX3NjYWxlID4+ IDEpKSAvDQo+ICsJCQljaGlwLT5hbHNfdGltZV9zY2FsZTsNCj4gKw0KPiArCS8qIGFkanVzdCBm b3IgYWN0aXZlIGdhaW4gc2NhbGUgKi8NCj4gKwlsdXggPj49IDEzOyAvKiB0YWJsZXMgaGF2ZSBm YWN0b3Igb2YgODE5MiBidWlsdGluIGZvciBhY2N1cmFjeSAqLw0KPiArCWx1eCA9IChsdXggKiBj aGlwLT50YW9zX3NldHRpbmdzLmFsc19nYWluX3RyaW0gKyA1MDApIC8gMTAwMDsNCj4gKwlpZiAo bHV4ID4gTUFYX0xVWCkgeyAvKiBjaGVjayBmb3Igb3ZlcmZsb3cgKi8NCj4gK3JldHVybl9tYXg6 DQo+ICsJCWx1eCA9IE1BWF9MVVg7DQpSZWFsbHkgdGhlIHJpZ2h0IHRoaW5nIHRvIGRvPyAgU3Vy ZWx5IHlvdSB3YW50IHRvIHJldHVybiBhbiBvdXQgb2YgcmFuZ2UgZXJyb3I/IFBlcmhhcHMgRVJB TkdFIHNvIHVzZXJzcGFjZSBrbm93cyB0aGUgdmFsdWUgaXMgZ2FyYmFnZS4gLSBOTyAtIENPVUxE IEJFIERVRSBUTyBTQVRVUkFUSU9OIC0gSU4gV0hJQ0ggQ0FTRSBVU0VSU1BBQ0UgU09VTEQgS05P VyBJVCdTIEFUIExJTUlULg0KPiArCX0NCj4gKw0KPiArCS8qIFVwZGF0ZSB0aGUgc3RydWN0dXJl IHdpdGggdGhlIGxhdGVzdCBWQUxJRCBsdXguICovDQo+ICsJY2hpcC0+YWxzX2N1cl9pbmZvLmx1 eCA9IGx1eDsNCj4gKwlyZXQgPSBsdXg7DQo+ICsNCj4gK291dF91bmxvY2s6DQo+ICsJbXV0ZXhf dW5sb2NrKCZjaGlwLT5hbHNfbXV0ZXgpOw0KPiArCXJldHVybiByZXQ7DQo+ICt9DQo+ICsNCj4g Ky8qDQo+ICsgKiBPYnRhaW4gc2luZ2xlIHJlYWRpbmcgYW5kIGNhbGN1bGF0ZSB0aGUgYWxzX2dh aW5fdHJpbSAobGF0ZXIgdXNlZA0KPiArICogdG8gZGVyaXZlIGFjdHVhbCBsdXgpLg0KPiArICog UmV0dXJuIHVwZGF0ZWQgZ2Fpbl90cmltIHZhbHVlLg0KPiArICovDQo+ICtpbnQgdGFvc19hbHNf Y2FsaWJyYXRlKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQpIHsNCj4gKwlzdHJ1Y3QgdHNsMjU4 eF9jaGlwICpjaGlwID0gaTJjX2dldF9jbGllbnRkYXRhKGNsaWVudCk7DQo+ICsJdTggcmVnX3Zh bDsNCj4gKwl1bnNpZ25lZCBpbnQgZ2Fpbl90cmltX3ZhbDsNCj4gKwlpbnQgcmV0Ow0KPiArCWlu dCBsdXhfdmFsOw0KPiArDQo+ICsJcmV0ID0gaTJjX3NtYnVzX3dyaXRlX2J5dGUoY2xpZW50LCAo VFNMMjU4WF9DTURfUkVHIHwgVFNMMjU4WF9DTlRSTCkpOw0KPiArCWlmIChyZXQgPCAwKSB7DQo+ ICsJCWRldl9lcnIoJmNsaWVudC0+ZGV2LCAidGFvc19hbHNfY2FsaWJyYXRlIGZhaWxlZCB0byBy ZWFjaCB0aGUiDQpBZ2FpbiwgZG9uJ3QgYnJlYWsgdGhpcyBzb3J0IG9mIHN0cmluZyB1cCBob3dl dmVyIG11Y2ggY2hlY2twYXRjaCByYW50cyBhdCB5b3UuCQkJLSBPSyAtIEpVU1QgUkVNRU1CRVIg WU9VIFNBSUQgU08NCj4gKwkJCSIgQ05UUkwgcmVnaXN0ZXIsIHJldD0lZFxuIiwgcmV0KTsNCj4g KwkJcmV0dXJuIHJldDsNCj4gKwl9DQo+ICsNCj4gKwlyZWdfdmFsID0gaTJjX3NtYnVzX3JlYWRf Ynl0ZShjbGllbnQpOw0KPiArCWlmICgocmVnX3ZhbCAmIChUU0wyNThYX0NOVExfQURDX0VOQkwg fCBUU0wyNThYX0NOVExfUFdST04pKQ0KPiArCQkJIT0gKFRTTDI1OFhfQ05UTF9BRENfRU5CTCB8 IFRTTDI1OFhfQ05UTF9QV1JPTikpIHsNCj4gKwkJZGV2X2VycigmY2xpZW50LT5kZXYsICJ0YW9z X2Fsc19jYWxpYnJhdGUgZmFpbGVkIGJlY2F1c2UgdGhlIg0KPiArCQkJIiBkZXZpY2UgaXMgbm90 IHBvd2VyZWQgb24gd2l0aCBBREMgZW5hYmxlZFxuIik7DQo+ICsJCXJldHVybiAtRU5PREFUQTsN Cj4gKwl9DQo+ICsNCj4gKwlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZShjbGllbnQsIChUU0wy NThYX0NNRF9SRUcgfCBUU0wyNThYX1NUQVRVUykpOw0KPiArCWlmIChyZXQgPCAwKSB7DQo+ICsJ CWRldl9lcnIoJmNsaWVudC0+ZGV2LCAidGFvc19hbHNfY2FsaWJyYXRlIGZhaWxlZCB0byByZWFj aCB0aGUiDQo+ICsJCQkiIFNUQVRVUyByZWdpc3RlciwgcmV0PSVkXG4iLCByZXQpOw0KPiArCQly ZXR1cm4gcmV0Ow0KPiArCX0NCj4gKwlyZWdfdmFsID0gaTJjX3NtYnVzX3JlYWRfYnl0ZShjbGll bnQpOw0KPiArDQo+ICsJaWYgKChyZWdfdmFsICYgVFNMMjU4WF9TVEFfQURDVkFMSUQpICE9IFRT TDI1OFhfU1RBX0FEQ1ZBTElEKSB7DQo+ICsJCWRldl9lcnIoJmNsaWVudC0+ZGV2LCAidGFvc19h bHNfY2FsaWJyYXRlIGZhaWxlZCBiZWNhdXNlIHRoZSINCj4gKwkJCSIgU1RBVFVTIGRpZCBub3Qg aW5kaWNhdGUgQURDIHZhbGlkLlxuIik7DQo+ICsJCXJldHVybiAtRU5PREFUQTsNCj4gKwl9DQo+ ICsJbHV4X3ZhbCA9IHRhb3NfZ2V0X2x1eChjbGllbnQpOw0KPiArCWlmIChsdXhfdmFsIDwgMCkg ew0KPiArCQlkZXZfZXJyKCZjbGllbnQtPmRldiwgInRhb3NfYWxzX2NhbGlicmF0ZSBmYWlsZWQg dG8gZ2V0IGx1eFxuIik7DQo+ICsJCXJldHVybiBsdXhfdmFsOw0KPiArCX0NCj4gKwlnYWluX3Ry aW1fdmFsID0gKHVuc2lnbmVkIGludCkgKCgoY2hpcC0+dGFvc19zZXR0aW5ncy5hbHNfY2FsX3Rh cmdldCkNCj4gKwkJCSogY2hpcC0+dGFvc19zZXR0aW5ncy5hbHNfZ2Fpbl90cmltKSAvIGx1eF92 YWwpOw0KPiArDQo+ICsJZGV2X2luZm8oJmNsaWVudC0+ZGV2LCAidGFvc19zZXR0aW5ncy5hbHNf Y2FsX3RhcmdldCA9ICVkXG4iDQo+ICsJCSJ0YW9zX3NldHRpbmdzLmFsc19nYWluX3RyaW0gPSAl ZFxubHV4X3ZhbCA9ICVkXG4iLA0KPiArCQljaGlwLT50YW9zX3NldHRpbmdzLmFsc19jYWxfdGFy Z2V0LA0KPiArCQljaGlwLT50YW9zX3NldHRpbmdzLmFsc19nYWluX3RyaW0sDQo+ICsJCWx1eF92 YWwpOw0KPiArDQo+ICsJaWYgKChnYWluX3RyaW1fdmFsIDwgMjUwKSB8fCAoZ2Fpbl90cmltX3Zh bCA+IDQwMDApKSB7DQo+ICsJCWRldl9lcnIoJmNsaWVudC0+ZGV2LCAidGFvc19hbHNfY2FsaWJy YXRlIGZhaWxlZCBiZWNhdXNlIg0KPiArCQkJInRyaW1fdmFsIG9mICVkIGlzIG91dCBvZiByYW5n ZVxuIiwgZ2Fpbl90cmltX3ZhbCk7DQo+ICsJCXJldHVybiAtRU5PREFUQTsNCj4gKwl9DQo+ICsJ Y2hpcC0+dGFvc19zZXR0aW5ncy5hbHNfZ2Fpbl90cmltID0gKGludCkgZ2Fpbl90cmltX3ZhbDsN Cj4gKw0KPiArCXJldHVybiAoaW50KSBnYWluX3RyaW1fdmFsOw0KPiArfQ0KPiArDQo+ICsvKg0K PiArICogVHVybiB0aGUgZGV2aWNlIG9uLg0KPiArICogQ29uZmlndXJhdGlvbiBtdXN0IGJlIHNl dCBiZWZvcmUgY2FsbGluZyB0aGlzIGZ1bmN0aW9uLg0KPiArICovDQo+ICtzdGF0aWMgaW50IHRh b3NfY2hpcF9vbihzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50KSB7DQo+ICsJaW50IGk7DQo+ICsJ aW50IHJldCA9IDA7DQo+ICsJdTggKnVQOw0KPiArCXU4IHV0bXA7DQo+ICsJaW50IGFsc19jb3Vu dDsNCj4gKwlpbnQgYWxzX3RpbWU7DQo+ICsJc3RydWN0IHRzbDI1OHhfY2hpcCAqY2hpcCA9IGky Y19nZXRfY2xpZW50ZGF0YShjbGllbnQpOw0KPiArDQphbmQ/DQo+ICsJLyogYW5kIG1ha2Ugc3Vy ZSB3ZSdyZSBub3QgYWxyZWFkeSBvbiAqLw0KPiArCWlmIChjaGlwLT50YW9zX2NoaXBfc3RhdHVz ID09IFRBT1NfQ0hJUF9XT1JLSU5HKSB7DQo+ICsJCS8qIGlmIGZvcmNpbmcgYSByZWdpc3RlciB1 cGRhdGUgLSB0dXJuIG9mZiwgdGhlbiBvbiAqLw0KPiArCQlkZXZfaW5mbygmY2xpZW50LT5kZXYs ICJkZXZpY2UgaXMgYWxyZWFkeSBlbmFibGVkXG4iKTsNCk5vdCBzdXJlIHdoYXQgdGhlIHJpZ2h0 IGVycm9yIGlzIGhlcmUsIGJ1dCBzaG91bGQgYmUgbW9yZSBzcGVjaWZpYyB0aGFuIHRoYXQuCS0g T0sgLSAgQlVUICBNRVNTQUdFIFRPIElORElDQVRFIElULCBVU0VSU1BBQ0UgQ09VTEQgSEFWRSBC RUVOIFRSWUlORyBUTyBUVVJOIElUIE9OIEZPUiBBIE5VTUJFUiBPRiBSRUFTT05TDQo+ICsJCXJl dHVybiAtMTsNCj4gKwl9DQo+ICsNCj4gKwkvKiBkZXRlcm1pbmUgYWxzIGludGVncmF0aW9uIHJl Z3N0ZXIgKi8NCj4gKwlhbHNfY291bnQgPSAoY2hpcC0+dGFvc19zZXR0aW5ncy5hbHNfdGltZSAq IDEwMCArIDEzNSkgLyAyNzA7DQo+ICsJaWYgKGFsc19jb3VudCA9PSAwKQ0KPiArCQlhbHNfY291 bnQgPSAxOyAvKiBlbnN1cmUgYXQgbGVhc3Qgb25lIGN5Y2xlICovDQo+ICsNCj4gKw0KPiArCS8q IGNvbnZlcnQgYmFjayB0byB0aW1lIChlbmNvbXBhc3NlcyBvdmVycmlkZXMpICovDQo+ICsJYWxz X3RpbWUgPSAoYWxzX2NvdW50ICogMjcgKyA1KSAvIDEwOw0KPiArCWNoaXAtPnRhb3NfY29uZmln W1RTTDI1OFhfQUxTX1RJTUVdID0gMjU2IC0gYWxzX2NvdW50Ow0KPiArDQo+ICsNCkJvbnVzIGJs YW5rIGxpbmVzLiAgT25lIGlzIHBsZW50eSB0byBicmVhayB1cCBjb2RlLgkJCQktIEZJWEVEDQo+ ICsJLyogU2V0IHRoZSBnYWluIGJhc2VkIG9uIHRhb3Nfc2V0dGluZ3Mgc3RydWN0ICovDQo+ICsJ Y2hpcC0+dGFvc19jb25maWdbVFNMMjU4WF9HQUlOXSA9IGNoaXAtPnRhb3Nfc2V0dGluZ3MuYWxz X2dhaW47DQo+ICsNCj4gKw0KPiArCS8qIHNldCBnbG9iYWxzIHJlIHNjYWxpbmcgYW5kIHNhdHVy YXRpb24gKi8NClRoZXkgYXJlbid0IGdsb2JhbHMJCQkJCQkJCS0gQ09SUkVDVCBDSEFOR0VEIENP TU1FTlQNCj4gKwljaGlwLT5hbHNfc2F0dXJhdGlvbiA9IGFsc19jb3VudCAqIDkyMjsgLyogOTAl IG9mIGZ1bGwgc2NhbGUgKi8NCj4gKwljaGlwLT5hbHNfdGltZV9zY2FsZSA9IChhbHNfdGltZSAr IDI1KSAvIDUwOw0KPiArDQo+ICsJLyogU0tBVEUgU3BlY2lmaWMgcG93ZXItb24gLyBhZGMgZW5h YmxlIHNlcXVlbmNlDQo+ICsJICogUG93ZXIgb24gdGhlIGRldmljZSAxc3QuICovDQo+ICsJdXRt cCA9IFRTTDI1OFhfQ05UTF9QV1JPTjsNCj4gKwlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZV9k YXRhKGNsaWVudCwgVFNMMjU4WF9DTURfUkVHIHwgVFNMMjU4WF9DTlRSTCwNCj4gKwkJCQkJdXRt cCk7DQo+ICsJaWYgKHJldCA8IDApIHsNCj4gKwkJZGV2X2VycigmY2xpZW50LT5kZXYsICJ0YW9z X2NoaXBfb24gZmFpbGVkIG9uIENOVFJMIHJlZy5cbiIpOw0KPiArCQlyZXR1cm4gLTE7DQo+ICsJ fQ0KPiArDQo+ICsJLyogVXNlIHRoZSBmb2xsb3dpbmcgc2hhZG93IGNvcHkgZm9yIG91ciBkZWxh eSBiZWZvcmUgZW5hYmxpbmcgQURDLg0KPiArCSAqIFdyaXRlIGFsbCB0aGUgcmVnaXN0ZXJzLiAq Lw0KPiArCWZvciAoaSA9IDAsIHVQID0gY2hpcC0+dGFvc19jb25maWc7IGkgPCBUQU9TX1JFR19N QVg7IGkrKykgew0KPiArCQlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwg VFNMMjU4WF9DTURfUkVHICsgaSwNCj4gKwkJCQkJCSp1UCsrKTsNCj4gKwkJaWYgKHJldCA8IDAp IHsNCj4gKwkJCWRldl9lcnIoJmNsaWVudC0+ZGV2LA0KPiArCQkJCSJ0YW9zX2NoaXBfb24gZmFp bGVkIG9uIHJlZyAlZC5cbiIsIGkpOw0KPiArCQkJcmV0dXJuIC0xOw0KPiArCQl9DQo+ICsJfQ0K PiArDQo+ICsJbWRlbGF5KDMpOw0KPiArCS8qIE5PVyBlbmFibGUgdGhlIEFEQw0KPiArCSAqIGlu aXRpYWxpemUgdGhlIGRlc2lyZWQgbW9kZSBvZiBvcGVyYXRpb24gKi8NCj4gKwl1dG1wID0gVFNM MjU4WF9DTlRMX1BXUk9OIHwgVFNMMjU4WF9DTlRMX0FEQ19FTkJMOw0KPiArCXJldCA9IGkyY19z bWJ1c193cml0ZV9ieXRlX2RhdGEoY2xpZW50LCBUU0wyNThYX0NNRF9SRUcgfCBUU0wyNThYX0NO VFJMLA0KPiArCQkJCQl1dG1wKTsNCj4gKwlpZiAocmV0IDwgMCkgew0KPiArCQlkZXZfZXJyKCZj bGllbnQtPmRldiwgInRhb3NfY2hpcF9vbiBmYWlsZWQgb24gMm5kIENUUkwgcmVnLlxuIik7DQo+ ICsJCXJldHVybiAtMTsNCj4gKwl9DQo+ICsJY2hpcC0+dGFvc19jaGlwX3N0YXR1cyA9IFRBT1Nf Q0hJUF9XT1JLSU5HOw0KQ29tbWVudCBpcyByYXRoZXIgb2J2aW91cy4uLgkJCQkJCS0gRE9ORSBS RU1PVkVEIENPTU1FTlQNCg0KPiArCXJldHVybiByZXQ7IC8qIHJldHVybnMgcmVzdWx0IG9mIGxh c3QgaTJjd3JpdGUgKi8gfQ0KPiArDQo+ICsvKiBUdXJuIHRoZSBkZXZpY2UgT0ZGLiAqLw0KPiAr c3RhdGljIGludCB0YW9zX2NoaXBfb2ZmKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQpIHsNCj4g KwlzdHJ1Y3QgdHNsMjU4eF9jaGlwICpjaGlwID0gaTJjX2dldF9jbGllbnRkYXRhKGNsaWVudCk7 DQo+ICsJaW50IHJldDsNCj4gKwl1OCB1dG1wOw0KPiArDQo+ICsJLyogdHVybiBkZXZpY2Ugb2Zm ICovDQo+ICsJY2hpcC0+dGFvc19jaGlwX3N0YXR1cyA9IFRBT1NfQ0hJUF9TTEVFUDsNCj4gKwl1 dG1wID0gMHgwMDsNCj4gKwlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZV9kYXRhKGNsaWVudCwg VFNMMjU4WF9DTURfUkVHIHwgVFNMMjU4WF9DTlRSTCwNCj4gKwkJCQkJdXRtcCk7DQo+ICsJcmV0 dXJuIHJldDsNCj4gK30NCj4gKw0KPiArLyogU3lzZnMgSW50ZXJmYWNlIEZ1bmN0aW9ucyAqLw0K PiArc3RhdGljIHNzaXplX3QgdGFvc19kZXZpY2VfaWQoc3RydWN0IGRldmljZSAqZGV2LA0KPiAr ICAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLCBjaGFyICpidWYpIHsNCj4gKwlyZXR1 cm4gc3ByaW50ZihidWYsICIlc1xuIiwgREVWSUNFX0lEKTsgfQ0KPiArDQo+ICtzdGF0aWMgc3Np emVfdCB0YW9zX3Bvd2VyX3N0YXRlX3Nob3coc3RydWN0IGRldmljZSAqZGV2LA0KPiArICAgIHN0 cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLCBjaGFyICpidWYpIHsNCj4gKwlzdHJ1Y3QgaWlv X2RldiAqaW5kaW9fZGV2ID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQo+ICsJc3RydWN0IHRzbDI1 OHhfY2hpcCAqY2hpcCA9IGluZGlvX2Rldi0+ZGV2X2RhdGE7DQo+ICsNCj4gKwlyZXR1cm4gc3By aW50ZihidWYsICIlZFxuIiwgY2hpcC0+dGFvc19jaGlwX3N0YXR1cyk7IH0NCj4gKw0KPiArc3Rh dGljIHNzaXplX3QgdGFvc19wb3dlcl9zdGF0ZV9zdG9yZShzdHJ1Y3QgZGV2aWNlICpkZXYsDQo+ ICsgICAgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNvbnN0IGNoYXIgKmJ1Ziwgc2l6 ZV90IGxlbikgew0KPiArCXN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYgPSBkZXZfZ2V0X2RydmRh dGEoZGV2KTsNCj4gKwlzdHJ1Y3QgdHNsMjU4eF9jaGlwICpjaGlwID0gaW5kaW9fZGV2LT5kZXZf ZGF0YTsNCj4gKwl1bnNpZ25lZCBsb25nIHZhbHVlOw0KPiArDQo+ICsJaWYgKHN0cmljdF9zdHJ0 b3VsKGJ1ZiwgMCwgJnZhbHVlKSkNCj4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+ICsNCj4gKwlpZiAo dmFsdWUgPT0gMCkNCj4gKwkJdGFvc19jaGlwX29mZihjaGlwLT5jbGllbnQpOw0KPiArCWVsc2UN Cj4gKwkJdGFvc19jaGlwX29uKGNoaXAtPmNsaWVudCk7DQo+ICsNCj4gKwlyZXR1cm4gbGVuOw0K PiArfQ0KPiArDQo+ICtzdGF0aWMgc3NpemVfdCB0YW9zX2dhaW5fc2hvdyhzdHJ1Y3QgZGV2aWNl ICpkZXYsDQo+ICsgICAgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNoYXIgKmJ1Zikg ew0KPiArCXN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsN Cj4gKwlzdHJ1Y3QgdHNsMjU4eF9jaGlwICpjaGlwID0gaW5kaW9fZGV2LT5kZXZfZGF0YTsNCj4g Kw0KPiArCXJldHVybiBzcHJpbnRmKGJ1ZiwgIiVkXG4iLCBjaGlwLT50YW9zX3NldHRpbmdzLmFs c19nYWluKTsgfQ0KPiArDQo+ICtzdGF0aWMgc3NpemVfdCB0YW9zX2dhaW5fc3RvcmUoc3RydWN0 IGRldmljZSAqZGV2LA0KPiArICAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLCBjb25z dCBjaGFyICpidWYsIHNpemVfdCBsZW4pIHsNCj4gKwlzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2 ID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQo+ICsJc3RydWN0IHRzbDI1OHhfY2hpcCAqY2hpcCA9 IGluZGlvX2Rldi0+ZGV2X2RhdGE7DQo+ICsJdW5zaWduZWQgbG9uZyB2YWx1ZTsNCj4gKwlpZiAo c3RyaWN0X3N0cnRvdWwoYnVmLCAwLCAmdmFsdWUpKQ0KPiArCQlyZXR1cm4gLUVJTlZBTDsNCj4g KwlpZiAodmFsdWUpIHsNCj4gKwkJaWYgKHZhbHVlID4gNCkgew0KPiArCQkJZGV2X2VycihkZXYs ICJJbnZhbGlkIEdhaW4gSW5kZXhcbiIpOw0KPiArCQkJcmV0dXJuIC0xOw0KRUlOVkFMDQo+ICsJ CX0gZWxzZSB7DQo+ICsJCQljaGlwLT50YW9zX3NldHRpbmdzLmFsc19nYWluID0gdmFsdWU7DQo+ ICsJCX0NClNvIHRoaXMgc2V0cyB0aGUgdmFsdWUgaW4gdGhlIGxvY2FsIGNhY2hlLiAgV2hlbiBk b2VzIGl0IGdldCB3cml0dGVuIHRvIHRoZSBkZXZpY2U/CS0gRVZFUllUSU1FIENISVBfT04gSVMg Q0FMTEVEDQo+ICsJfQ0KPiArCXJldHVybiBsZW47DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBzc2l6 ZV90IHRhb3NfYWxzX3RpbWVfc2hvdyhzdHJ1Y3QgZGV2aWNlICpkZXYsDQo+ICsgICAgc3RydWN0 IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNoYXIgKmJ1Zikgew0KPiArCXN0cnVjdCBpaW9fZGV2 ICppbmRpb19kZXYgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsNCj4gKwlzdHJ1Y3QgdHNsMjU4eF9j aGlwICpjaGlwID0gaW5kaW9fZGV2LT5kZXZfZGF0YTsNCj4gKw0KPiArCXJldHVybiBzcHJpbnRm KGJ1ZiwgIiVkXG4iLCBjaGlwLT50YW9zX3NldHRpbmdzLmFsc190aW1lKTsgfQ0KPiArDQo+ICtz dGF0aWMgc3NpemVfdCB0YW9zX2Fsc190aW1lX3N0b3JlKHN0cnVjdCBkZXZpY2UgKmRldiwNCj4g KyAgICBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY29uc3QgY2hhciAqYnVmLCBzaXpl X3QgbGVuKSB7DQo+ICsJc3RydWN0IGlpb19kZXYgKmluZGlvX2RldiA9IGRldl9nZXRfZHJ2ZGF0 YShkZXYpOw0KPiArCXN0cnVjdCB0c2wyNTh4X2NoaXAgKmNoaXAgPSBpbmRpb19kZXYtPmRldl9k YXRhOw0KPiArCXVuc2lnbmVkIGxvbmcgdmFsdWU7DQo+ICsNCj4gKwlpZiAoc3RyaWN0X3N0cnRv dWwoYnVmLCAwLCAmdmFsdWUpKQ0KPiArCQlyZXR1cm4gLUVJTlZBTDsNCj4gKw0KPiArCWlmICh2 YWx1ZSkNCj4gKwkJY2hpcC0+dGFvc19zZXR0aW5ncy5hbHNfdGltZSA9IHZhbHVlOw0KZWxzZT8g SXQncyBub3QgYmVlbiBzdWNlc3NmdWx5IHNldCBzbyByZXR1cm4gLUVJTlZBTAkJLSBET05FDQo+ ICsNCj4gKwlyZXR1cm4gbGVuOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgc3NpemVfdCB0YW9zX2Fs c190cmltX3Nob3coc3RydWN0IGRldmljZSAqZGV2LA0KPiArICAgIHN0cnVjdCBkZXZpY2VfYXR0 cmlidXRlICphdHRyLCBjaGFyICpidWYpIHsNCj4gKwlzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2 ID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQo+ICsJc3RydWN0IHRzbDI1OHhfY2hpcCAqY2hpcCA9 IGluZGlvX2Rldi0+ZGV2X2RhdGE7DQo+ICsNCj4gKwlyZXR1cm4gc3ByaW50ZihidWYsICIlZFxu IiwgY2hpcC0+dGFvc19zZXR0aW5ncy5hbHNfZ2Fpbl90cmltKTsNCj4gK30NCj4gKw0KPiArc3Rh dGljIHNzaXplX3QgdGFvc19hbHNfdHJpbV9zdG9yZShzdHJ1Y3QgZGV2aWNlICpkZXYsDQo+ICsg ICAgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90 IGxlbikgew0KPiArCXN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYgPSBkZXZfZ2V0X2RydmRhdGEo ZGV2KTsNCj4gKwlzdHJ1Y3QgdHNsMjU4eF9jaGlwICpjaGlwID0gaW5kaW9fZGV2LT5kZXZfZGF0 YTsNCj4gKwl1bnNpZ25lZCBsb25nIHZhbHVlOw0KPiArDQo+ICsJaWYgKHN0cmljdF9zdHJ0b3Vs KGJ1ZiwgMCwgJnZhbHVlKSkNCj4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+ICsNCj4gKwlpZiAodmFs dWUpDQo+ICsJCWNoaXAtPnRhb3Nfc2V0dGluZ3MuYWxzX2dhaW5fdHJpbSA9IHZhbHVlOw0KZWxz ZSByZXR1cm4gLUVJTlZBTAkJCQkJCQktIFVOTEVTUyBJJ00gTUlTU0lORyBTT01FVEhJTkcsIFRB S0VOIENBUkUgSU4gSU4gJ0lGJyBBQk9WRQ0KPiArDQo+ICsJcmV0dXJuIGxlbjsNCj4gK30NCj4g Kw0KPiArc3RhdGljIHNzaXplX3QgdGFvc19hbHNfY2FsX3RhcmdldF9zaG93KHN0cnVjdCBkZXZp Y2UgKmRldiwNCj4gKyAgICBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVm KSB7DQo+ICsJc3RydWN0IGlpb19kZXYgKmluZGlvX2RldiA9IGRldl9nZXRfZHJ2ZGF0YShkZXYp Ow0KPiArCXN0cnVjdCB0c2wyNTh4X2NoaXAgKmNoaXAgPSBpbmRpb19kZXYtPmRldl9kYXRhOw0K PiArDQo+ICsJcmV0dXJuIHNwcmludGYoYnVmLCAiJWRcbiIsIGNoaXAtPnRhb3Nfc2V0dGluZ3Mu YWxzX2NhbF90YXJnZXQpOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgc3NpemVfdCB0YW9zX2Fsc19j YWxfdGFyZ2V0X3N0b3JlKHN0cnVjdCBkZXZpY2UgKmRldiwNCj4gKyAgICBzdHJ1Y3QgZGV2aWNl X2F0dHJpYnV0ZSAqYXR0ciwgY29uc3QgY2hhciAqYnVmLCBzaXplX3QgbGVuKSB7DQo+ICsJc3Ry dWN0IGlpb19kZXYgKmluZGlvX2RldiA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0KPiArCXN0cnVj dCB0c2wyNTh4X2NoaXAgKmNoaXAgPSBpbmRpb19kZXYtPmRldl9kYXRhOw0KPiArCXVuc2lnbmVk IGxvbmcgdmFsdWU7DQo+ICsNCj4gKwlpZiAoc3RyaWN0X3N0cnRvdWwoYnVmLCAwLCAmdmFsdWUp KQ0KPiArCQlyZXR1cm4gLUVJTlZBTDsNCj4gKw0KPiArCWlmICh2YWx1ZSkNCj4gKwkJY2hpcC0+ dGFvc19zZXR0aW5ncy5hbHNfY2FsX3RhcmdldCA9IHZhbHVlOw0KYWdhaW4sIGVsc2UgcmV0dXJu IC1FSU5WQUw7ICBVc2Vyc3BhY2UgcmVhbGx5IHdhbnRzIHRvIGtub3cgdGhpcyBmYWlsZWQuCQkt IFRBS0VOIENBUkUgSU4gSU4gJ0lGJyBBQk9WRQ0KPiArDQo+ICsJcmV0dXJuIGxlbjsNCj4gK30N Cj4gKw0KPiArc3RhdGljIHNzaXplX3QgdGFvc19sdXhfc2hvdyhzdHJ1Y3QgZGV2aWNlICpkZXYs IHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLA0KPiArICAgIGNoYXIgKmJ1ZikNCj4gK3sN Cj4gKwlzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2ID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQo+ ICsJc3RydWN0IHRzbDI1OHhfY2hpcCAqY2hpcCA9IGluZGlvX2Rldi0+ZGV2X2RhdGE7DQo+ICsJ aW50IGx1eCA9IDA7DQpubyBuZWVkIHRvIGFzc2lnbi4JCQkJCQkJCS0gRE9ORQ0KPiArDQo+ICsJ bHV4ID0gdGFvc19nZXRfbHV4KGNoaXAtPmNsaWVudCk7DQo+ICsNCj4gKwlyZXR1cm4gc3ByaW50 ZihidWYsICIlZFxuIiwgbHV4KTsNCj4gK30NCj4gKw0KPiArc3RhdGljIHNzaXplX3QgdGFvc19k b19jYWxpYnJhdGUoc3RydWN0IGRldmljZSAqZGV2LA0KPiArICAgIHN0cnVjdCBkZXZpY2VfYXR0 cmlidXRlICphdHRyLCBjb25zdCBjaGFyICpidWYsIHNpemVfdCBsZW4pIHsNCj4gKwlzdHJ1Y3Qg aWlvX2RldiAqaW5kaW9fZGV2ID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQo+ICsJc3RydWN0IHRz bDI1OHhfY2hpcCAqY2hpcCA9IGluZGlvX2Rldi0+ZGV2X2RhdGE7DQo+ICsJdW5zaWduZWQgbG9u ZyB2YWx1ZTsNCj4gKw0KPiArCWlmIChzdHJpY3Rfc3RydG91bChidWYsIDAsICZ2YWx1ZSkpDQo+ ICsJCXJldHVybiAtRUlOVkFMOw0KPiArDQo+ICsJaWYgKHZhbHVlID09IDEpDQo+ICsJCXRhb3Nf YWxzX2NhbGlicmF0ZShjaGlwLT5jbGllbnQpOw0KZWxzZSByZXR1cm4gLUVJTlZBTDsJCQkJCQkJ CS0gVEFLRU4gQ0FSRSBJTiBJTiAnSUYnIEFCT1ZFDQo+ICsNCj4gKwlyZXR1cm4gbGVuOw0KPiAr fQ0KPiArDQo+ICtzdGF0aWMgc3NpemVfdCB0YW9zX2x1eHRhYmxlX3Nob3coc3RydWN0IGRldmlj ZSAqZGV2LA0KPiArICAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLCBjaGFyICpidWYp IHsNCj4gKwlpbnQgaTsNCj4gKwlpbnQgb2Zmc2V0ID0gMDsNCj4gKw0KPiArCWZvciAoaSA9IDA7 IGkgPCBBUlJBWV9TSVpFKHRhb3NfZGV2aWNlX2x1eCk7IGkrKykgew0KPiArCQlvZmZzZXQgKz0g c3ByaW50ZihidWYgKyBvZmZzZXQsICIlZCwlZCwlZCwiLA0KPiArCQkJCSAgdGFvc19kZXZpY2Vf bHV4W2ldLnJhdGlvLA0KPiArCQkJCSAgdGFvc19kZXZpY2VfbHV4W2ldLmNoMCwNCj4gKwkJCQkg IHRhb3NfZGV2aWNlX2x1eFtpXS5jaDEpOw0KPiArCQlpZiAodGFvc19kZXZpY2VfbHV4W2ldLnJh dGlvID09IDApIHsNCj4gKwkJCS8qIFdlIGp1c3QgcHJpbnRlZCB0aGUgZmlyc3QgIjAiIGVudHJ5 Lg0KPiArCQkJICogTm93IGdldCByaWQgb2YgdGhlIGV4dHJhICIsIiBhbmQgYnJlYWsuICovDQo+ ICsJCQlvZmZzZXQtLTsNCj4gKwkJCWJyZWFrOw0KPiArCQl9DQo+ICsJfQ0KPiArDQo+ICsJb2Zm c2V0ICs9IHNwcmludGYoYnVmICsgb2Zmc2V0LCAiXG4iKTsNCj4gKwlyZXR1cm4gb2Zmc2V0Ow0K PiArfQ0KPiArDQo+ICtzdGF0aWMgc3NpemVfdCB0YW9zX2x1eHRhYmxlX3N0b3JlKHN0cnVjdCBk ZXZpY2UgKmRldiwNCj4gKyAgICBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY29uc3Qg Y2hhciAqYnVmLCBzaXplX3QgbGVuKSB7DQo+ICsJc3RydWN0IGlpb19kZXYgKmluZGlvX2RldiA9 IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0KPiArCXN0cnVjdCB0c2wyNTh4X2NoaXAgKmNoaXAgPSBp bmRpb19kZXYtPmRldl9kYXRhOyAjZGVmaW5lIA0KPiArTUFYX0xVWF9UQUJMRV9GSUVMRFMgMzMJ CQkJCQkJLSBET05FDQpJJ2QgbG9vc2UgdGhpcyBkZWZpbmUuDQo+ICsJaW50IHZhbHVlW01BWF9M VVhfVEFCTEVfRklFTERTXTsNCj4gKwlpbnQgbjsNCj4gKw0KPiArCWdldF9vcHRpb25zKGJ1Ziwg QVJSQVlfU0laRSh2YWx1ZSksIHZhbHVlKTsNCj4gKw0KPiArCS8qIFdlIG5vdyBoYXZlIGFuIGFy cmF5IG9mIGludHMgc3RhcnRpbmcgYXQgdmFsdWVbMV0sIGFuZA0KPiArCSAqIGVudW1lcmF0ZWQg YnkgdmFsdWVbMF0uDQo+ICsJICogV2UgZXhwZWN0IGVhY2ggZ3JvdXAgb2YgdGhyZWUgaW50cyBp cyBvbmUgdGFibGUgZW50cnksDQo+ICsJICogYW5kIHRoZSBsYXN0IHRhYmxlIGVudHJ5IGlzIGFs bCAwLg0KPiArCSAqLw0KPiArCW4gPSB2YWx1ZVswXTsNCiAgcHJlZmVyIHRvIHNlZSBBUlJBWV9T SVpFKHZhbHVlKSB0aGFuIHRoZSBkZWZpbmUuICAJCQkJLSBBR1JFRUQgLSBET05FDQo+ICsJaWYg KChuICUgMykgfHwgbiA8IDYgfHwgbiA+IChNQVhfTFVYX1RBQkxFX0ZJRUxEUyAtIDMpKSB7DQo+ ICsJCWRldl9pbmZvKGRldiwgIkxVWCBUQUJMRSBJTlBVVCBFUlJPUiAxIFZhbHVlWzBdPSVkXG4i LCBuKTsNCj4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+ICsJfQ0KPiArCWlmICgodmFsdWVbKG4gLSAy KV0gfCB2YWx1ZVsobiAtIDEpXSB8IHZhbHVlW25dKSAhPSAwKSB7DQo+ICsJCWRldl9pbmZvKGRl diwgIkxVWCBUQUJMRSBJTlBVVCBFUlJPUiAyIFZhbHVlWzBdPSVkXG4iLCBuKTsNCj4gKwkJcmV0 dXJuIC1FSU5WQUw7DQo+ICsJfQ0KPiArDQo+ICsJaWYgKGNoaXAtPnRhb3NfY2hpcF9zdGF0dXMg PT0gVEFPU19DSElQX1dPUktJTkcpDQo+ICsJCXRhb3NfY2hpcF9vZmYoY2hpcC0+Y2xpZW50KTsN Cj4gKw0KPiArCS8qIFplcm8gb3V0IHRoZSB0YWJsZSAqLw0KPiArCW1lbXNldCh0YW9zX2Rldmlj ZV9sdXgsIDAsIHNpemVvZih0YW9zX2RldmljZV9sdXgpKTsNCj4gKwltZW1jcHkodGFvc19kZXZp Y2VfbHV4LCAmdmFsdWVbMV0sICh2YWx1ZVswXSAqIDQpKTsNCj4gKw0KPiArCXRhb3NfY2hpcF9v bihjaGlwLT5jbGllbnQpOw0KPiArDQo+ICsJcmV0dXJuIGxlbjsNCj4gK30NCj4gKw0KPiArc3Rh dGljIHU4IHJlZ19pbmRleDsNCj4gKw0KQXMgc3RhdGVkIGFib3ZlIHRoZXNlIG5lZWQgdG8gZ28g YmVmb3JlIHdlIHRha2UgdGhpcyBkcml2ZXIuCQkJLSBET05FICAtIEJVVCBUSEVTRSBXRVJFIE5F RURFRCBCWSBVU0VSU1BBQ0UgQVBQIEZPUiBDUkVBVElORyBORVcgTFVYIEVRVUFUSU9OIENPRUZG cyBQUklPUiBUTyBQUk9EVUNUSU9ODQoJCQkJCQkJCQkJCU5FVkVSIFRIRSBMRVNTIC0gR09ORS4N Cj4gKy8qIFNldHMgYSBwb2ludGVyIHRvIGEgcmVnaXN0ZXIgZm9yIFIvVyB2aWEgc3lzZnMgKi8g c3RhdGljIHNzaXplX3QgDQo+ICt0YW9zX3JlZ19vZmZzZXRfc2hvdyhzdHJ1Y3QgZGV2aWNlICpk ZXYsDQo+ICsgICAgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNoYXIgKmJ1Zikgew0K PiArICAgICAgcmV0dXJuIHNwcmludGYoYnVmLCAiJWRcbiIsIHJlZ19pbmRleCk7DQo+ICsgICAg ICByZXR1cm4gMDsNCj4gK30NCj4gKw0KPiArc3RhdGljIHNzaXplX3QgdGFvc19yZWdfb2Zmc2V0 X3N0b3JlKHN0cnVjdCBkZXZpY2UgKmRldiwNCj4gKyAgICBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0 ZSAqYXR0ciwgY29uc3QgY2hhciAqYnVmLCBzaXplX3QgbGVuKSB7DQo+ICsJdW5zaWduZWQgbG9u ZyB2YWx1ZTsNCj4gKwlpZiAoc3RyaWN0X3N0cnRvdWwoYnVmLCAwLCAmdmFsdWUpKQ0KPiArCQly ZXR1cm4gLUVJTlZBTDsNCj4gKw0KPiArCWlmICh2YWx1ZSA+IE1BWF9ERVZJQ0VfUkVHUykgew0K PiArCQlkZXZfZXJyKGRldiwgInJlZ2lzdGVyIG9mZnNldCBleGNlZWRzIE1BWFxuIik7DQo+ICsJ CXJldHVybiAtMTsNCj4gKwl9IGVsc2Ugew0KPiArCQlyZWdfaW5kZXggPSB2YWx1ZTsNCj4gKwl9 DQo+ICtyZXR1cm4gbGVuOw0KPiArfQ0KPiArDQo+ICsvKiBSL1cgYSByZWdpc3RlciBmb3IgUi9X IHZpYSBzeXNmcyAqLyBzdGF0aWMgc3NpemVfdCANCj4gK3Rhb3NfcmVnX3Nob3coc3RydWN0IGRl dmljZSAqZGV2LA0KPiArICAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLCBjaGFyICpi dWYpIHsNCj4gKwlzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2ID0gZGV2X2dldF9kcnZkYXRhKGRl dik7DQo+ICsJc3RydWN0IHRzbDI1OHhfY2hpcCAqY2hpcCA9IGluZGlvX2Rldi0+ZGV2X2RhdGE7 DQo+ICsNCj4gKwl1OCB2YWx1ZSA9IDA7DQo+ICsJaW50IHJldCA9IDA7DQo+ICsNCj4gKwlyZXQg PSBpMmNfc21idXNfd3JpdGVfYnl0ZShjaGlwLT5jbGllbnQsDQo+ICsJCShUU0wyNThYX0NNRF9S RUcgfCByZWdfaW5kZXgpKTsNCj4gKwlpZiAocmV0IDwgMCkgew0KPiArCQlkZXZfZXJyKGRldiwg ImkyY19zbWJ1c193cml0ZV9ieXRlIHRvIGNtZCByZWcgZmFpbGVkICINCj4gKwkJCSJpbiB0YW9z X3JlZ19vZmZzZXRfc2hvdygpLCBlcnIgPSAlZFxuIiwgcmV0KTsNCj4gKwkJcmV0dXJuIHJldDsN Cj4gKwl9DQo+ICsJdmFsdWUgPSBpMmNfc21idXNfcmVhZF9ieXRlKGNoaXAtPmNsaWVudCk7DQo+ ICsJcmV0dXJuIHNwcmludGYoYnVmLCAiJWRcbiIsIHZhbHVlKTsNCj4gKw0KPiArcmV0dXJuIDA7 DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBzc2l6ZV90IHRhb3NfcmVnX3N0b3JlKHN0cnVjdCBkZXZp Y2UgKmRldiwNCj4gKyAgICBzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY29uc3QgY2hh ciAqYnVmLCBzaXplX3QgbGVuKSB7DQo+ICsJc3RydWN0IGlpb19kZXYgKmluZGlvX2RldiA9IGRl dl9nZXRfZHJ2ZGF0YShkZXYpOw0KPiArCXN0cnVjdCB0c2wyNTh4X2NoaXAgKmNoaXAgPSBpbmRp b19kZXYtPmRldl9kYXRhOw0KPiArDQo+ICsJdW5zaWduZWQgbG9uZyB2YWx1ZSA9IDA7DQo+ICsJ aW50IHJldCA9IDA7DQo+ICsNCj4gKwlpZiAoc3RyaWN0X3N0cnRvdWwoYnVmLCAwLCAmdmFsdWUp KQ0KPiArCQlyZXR1cm4gLUVJTlZBTDsNCj4gKw0KPiArCXJldCA9IGkyY19zbWJ1c193cml0ZV9i eXRlX2RhdGEoY2hpcC0+Y2xpZW50LA0KPiArCQkoVFNMMjU4WF9DTURfUkVHIHwgcmVnX2luZGV4 KSwgdmFsdWUpOw0KPiArCWlmIChyZXQgPCAwKSB7DQo+ICsJCWRldl9lcnIoZGV2LCAiaTJjX3Nt YnVzX3dyaXRlX2J5dGVfZGF0YSBmYWlsZWQgaW4gIg0KPiArCQkJInRhb3NfcmVnX3N0b3JlKClc biIpOw0KPiArCQlyZXR1cm4gcmV0Ow0KPiArCX0NCj4gKw0KPiArcmV0dXJuIGxlbjsNCj4gK30N Cj4gKw0KPiArc3RhdGljIERFVklDRV9BVFRSKG5hbWUsIFNfSVJVR08sIHRhb3NfZGV2aWNlX2lk LCBOVUxMKTsgc3RhdGljIA0KPiArREVWSUNFX0FUVFIoZGV2aWNlX3N0YXRlLCBTX0lSVUdPIHwg U19JV1VTUiwNCj4gKwkJdGFvc19wb3dlcl9zdGF0ZV9zaG93LCB0YW9zX3Bvd2VyX3N0YXRlX3N0 b3JlKTsgc3RhdGljIA0KPiArREVWSUNFX0FUVFIoYWxzX2dhaW4sIFNfSVJVR08gfCBTX0lXVVNS LA0KPiArCQl0YW9zX2dhaW5fc2hvdywgdGFvc19nYWluX3N0b3JlKTsNCj4gK3N0YXRpYyBERVZJ Q0VfQVRUUihhbHNfdGltZSwgU19JUlVHTyB8IFNfSVdVU1IsDQo+ICsJCXRhb3NfYWxzX3RpbWVf c2hvdywgdGFvc19hbHNfdGltZV9zdG9yZSk7IHN0YXRpYyANCj4gK0RFVklDRV9BVFRSKGFsc190 cmltLCBTX0lSVUdPIHwgU19JV1VTUiwNCj4gKwkJdGFvc19hbHNfdHJpbV9zaG93LCB0YW9zX2Fs c190cmltX3N0b3JlKTsgc3RhdGljIA0KPiArREVWSUNFX0FUVFIoYWxzX3RhcmdldCwgU19JUlVH TyB8IFNfSVdVU1IsDQo+ICsJCXRhb3NfYWxzX2NhbF90YXJnZXRfc2hvdywgdGFvc19hbHNfY2Fs X3RhcmdldF9zdG9yZSk7IHN0YXRpYyANCj4gK0RFVklDRV9BVFRSKGx1eCwgU19JUlVHTywgdGFv c19sdXhfc2hvdywgTlVMTCk7IHN0YXRpYyANCj4gK0RFVklDRV9BVFRSKGNhbGlicmF0ZSwgU19J V1VTUiwgTlVMTCwgdGFvc19kb19jYWxpYnJhdGUpOyBzdGF0aWMgDQo+ICtERVZJQ0VfQVRUUihs dXhfdGFibGUsIFNfSVJVR08gfCBTX0lXVVNSLA0KPiArCQl0YW9zX2x1eHRhYmxlX3Nob3csIHRh b3NfbHV4dGFibGVfc3RvcmUpOyBzdGF0aWMgDQo+ICtERVZJQ0VfQVRUUihyZWdfb2Zmc2V0LCBT X0lSVUdPIHwgU19JV1VTUiwNCj4gKyAgICAgIHRhb3NfcmVnX29mZnNldF9zaG93LA0KPiArICAg ICAgdGFvc19yZWdfb2Zmc2V0X3N0b3JlKTsNCj4gK3N0YXRpYyBERVZJQ0VfQVRUUihyZWcsIFNf SVJVR08gfCBTX0lXVVNSLA0KPiArICAgICAgdGFvc19yZWdfc2hvdywNCj4gKyAgICAgIHRhb3Nf cmVnX3N0b3JlKTsNCj4gKw0KPiArDQo+ICtzdGF0aWMgc3RydWN0IGF0dHJpYnV0ZSAqc3lzZnNf YXR0cnNfY3RybFtdID0gew0KPiArCSZkZXZfYXR0cl9uYW1lLmF0dHIsDQo+ICsJJmRldl9hdHRy X2RldmljZV9zdGF0ZS5hdHRyLA0KPiArCSZkZXZfYXR0cl9hbHNfZ2Fpbi5hdHRyLA0KPiArCSZk ZXZfYXR0cl9hbHNfdGltZS5hdHRyLA0KPiArCSZkZXZfYXR0cl9hbHNfdHJpbS5hdHRyLA0KPiAr CSZkZXZfYXR0cl9hbHNfdGFyZ2V0LmF0dHIsDQo+ICsJJmRldl9hdHRyX2x1eC5hdHRyLA0KPiAr CSZkZXZfYXR0cl9jYWxpYnJhdGUuYXR0ciwNCj4gKwkmZGV2X2F0dHJfbHV4X3RhYmxlLmF0dHIs DQpTcGFjZXMgaW5zdGVhZCBvZiB0YWIgaGVyZS4NCj4gKyAgICAmZGV2X2F0dHJfcmVnX29mZnNl dC5hdHRyLA0KPiArICAgICZkZXZfYXR0cl9yZWcuYXR0ciwNCj4gKwlOVUxMDQo+ICt9Ow0KPiAr DQo+ICtzdGF0aWMgc3RydWN0IGF0dHJpYnV0ZV9ncm91cCB0c2wyNTh4X2F0dHJpYnV0ZV9ncm91 cCA9IHsNCj4gKwkuYXR0cnMgPSBzeXNmc19hdHRyc19jdHJsLA0KPiArfTsNCj4gKw0KPiArLyog VXNlIHRoZSBkZWZhdWx0IHJlZ2lzdGVyIHZhbHVlcyB0byBpZGVudGlmeSB0aGUgVGFvcyBkZXZp Y2UgKi8gDQo+ICtzdGF0aWMgaW50IHRhb3Nfc2thdGVfZGV2aWNlKHVuc2lnbmVkIGNoYXIgKmJ1 ZnApIHsNCj4gKwlpZiAoKChidWZwW1RTTDI1OFhfQ0hJUElEXSAmIDB4ZjApID09IDB4OTApKQ0K PiArCQkvKiB0c2wyNTh4ICovDQo+ICsJCXJldHVybiAxOw0KPiArCS8qIGVsc2UgdW5rbm93biAq Lw0KPiArCXJldHVybiAwOw0KPiArfQ0KPiArDQo+ICsvKg0KPiArICogQ2xpZW50IHByb2JlIGZ1 bmN0aW9uIC0gV2hlbiBhIHZhbGlkIGRldmljZSBpcyBmb3VuZCwgdGhlIGRyaXZlcidzIA0KPiAr ZGV2aWNlDQo+ICsgKiBkYXRhIHN0cnVjdHVyZSBpcyB1cGRhdGVkLCBhbmQgaW5pdGlhbGl6YXRp b24gY29tcGxldGVzIHN1Y2Nlc3NmdWxseS4NCj4gKyAqLw0KPiArc3RhdGljIGludCBfX2Rldmlu aXQgdGFvc19wcm9iZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50cCwNCj4gKwkJICAgICAgY29u c3Qgc3RydWN0IGkyY19kZXZpY2VfaWQgKmlkcCkgew0KPiArCWludCBpLCByZXQgPSAwOw0KPiAr CXVuc2lnbmVkIGNoYXIgYnVmW01BWF9ERVZJQ0VfUkVHU107DQo+ICsJc3RhdGljIHN0cnVjdCB0 c2wyNTh4X2NoaXAgKmNoaXA7DQo+ICsNCj4gKwlpZiAoIWkyY19jaGVja19mdW5jdGlvbmFsaXR5 KGNsaWVudHAtPmFkYXB0ZXIsDQo+ICsJCUkyQ19GVU5DX1NNQlVTX0JZVEVfREFUQSkpIHsNCj4g KwkJZGV2X2VycigmY2xpZW50cC0+ZGV2LA0KPiArCQkJInRhb3NfcHJvYmUoKSAtIGkyYyBzbWJ1 cyBieXRlIGRhdGEgIg0KPiArCQkJImZ1bmN0aW9ucyB1bnN1cHBvcnRlZFxuIik7DQo+ICsJCXJl dHVybiAtRU9QTk9UU1VQUDsNCj4gKwl9DQo+ICsJaWYgKCFpMmNfY2hlY2tfZnVuY3Rpb25hbGl0 eShjbGllbnRwLT5hZGFwdGVyLA0KPiArCQlJMkNfRlVOQ19TTUJVU19XT1JEX0RBVEEpKSB7DQo+ ICsJCWRldl93YXJuKCZjbGllbnRwLT5kZXYsDQo+ICsJCQkidGFvc19wcm9iZSgpIC0gaTJjIHNt YnVzIHdvcmQgZGF0YSAiDQo+ICsJCQkiZnVuY3Rpb25zIHVuc3VwcG9ydGVkXG4iKTsNCj4gKwl9 DQo+ICsJaWYgKCFpMmNfY2hlY2tfZnVuY3Rpb25hbGl0eShjbGllbnRwLT5hZGFwdGVyLA0KPiAr CQlJMkNfRlVOQ19TTUJVU19CTE9DS19EQVRBKSkgew0KPiArCQlkZXZfZXJyKCZjbGllbnRwLT5k ZXYsDQo+ICsJCQkidGFvc19wcm9iZSgpIC0gaTJjIHNtYnVzIGJsb2NrIGRhdGEgIg0KPiArCQkJ ImZ1bmN0aW9ucyB1bnN1cHBvcnRlZFxuIik7DQo+ICsJfQ0KPiArDQo+ICsJY2hpcCA9IGttYWxs b2Moc2l6ZW9mKHN0cnVjdCB0c2wyNTh4X2NoaXApLCBHRlBfS0VSTkVMKTsNCj4gKwlpZiAoIWNo aXApIHsNCj4gKwkJZGV2X2VycigmY2xpZW50cC0+ZGV2LCAidGFvc19kZXZpY2VfZHJ2cjoga21h bGxvYyBmb3IgIg0KPiArCQkJInN0cnVjdCB0c2wyNTh4X2NoaXAgZmFpbGVkIGluIHRhb3NfcHJv YmUoKVxuIik7DQo+ICsJCXJldHVybiAtRU5PTUVNOw0KPiArCX0NCj4gKwltZW1zZXQoY2hpcCwg MCwgc2l6ZW9mKHN0cnVjdCB0c2wyNTh4X2NoaXApKTsNClVzZSBremFsbG9jIGluc3RlYWQgb2Yg a21hbGxvYyB0aGVuIHlvdSBkb24ndCBuZWVkIHRoZSBtZW1zZXQuCQkJLSBHUkVBVCAtIERPTkUN Cg0KPiArCWNoaXAtPmNsaWVudCA9IGNsaWVudHA7DQo+ICsJaTJjX3NldF9jbGllbnRkYXRhKGNs aWVudHAsIGNoaXApOw0KPiArDQo+ICsJbXV0ZXhfaW5pdCgmY2hpcC0+YWxzX211dGV4KTsNCj4g KwljaGlwLT50YW9zX2NoaXBfc3RhdHVzID0gVEFPU19DSElQX1VOS05PV047IC8qIHVuaW5pdGlh bGl6ZWQgdG8gc3RhcnQgKi8NCj4gKwltZW1jcHkoY2hpcC0+dGFvc19jb25maWcsIHRhb3NfY29u ZmlnLCBzaXplb2YoY2hpcC0+dGFvc19jb25maWcpKTsNCj4gKw0KPiArCWZvciAoaSA9IDA7IGkg PCBNQVhfREVWSUNFX1JFR1M7IGkrKykgew0KPiArCQlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0 ZShjbGllbnRwLA0KPiArCQkJCShUU0wyNThYX0NNRF9SRUcgfCAoVFNMMjU4WF9DTlRSTCArIGkp KSk7DQo+ICsJCWlmIChyZXQgPCAwKSB7DQo+ICsJCQlkZXZfZXJyKCZjbGllbnRwLT5kZXYsICJp MmNfc21idXNfd3JpdGVfYnl0ZSgpIHRvIGNtZCAiDQo+ICsJCQkJInJlZyBmYWlsZWQgaW4gdGFv c19wcm9iZSgpLCBlcnIgPSAlZFxuIiwgcmV0KTsNCj4gKwkJCWdvdG8gZmFpbDE7DQo+ICsJCX0N Cj4gKwkJYnVmW2ldID0gaTJjX3NtYnVzX3JlYWRfYnl0ZShjbGllbnRwKTsNCj4gKwl9DQo+ICsJ aWYgKCF0YW9zX3NrYXRlX2RldmljZShidWYpKSB7DQo+ICsJCWRldl9pbmZvKCZjbGllbnRwLT5k ZXYsICJpMmMgZGV2aWNlIGZvdW5kIGJ1dCBkb2VzIG5vdCBtYXRjaCAiDQo+ICsJCQkiZXhwZWN0 ZWQgaWQgaW4gdGFvc19wcm9iZSgpXG4iKTsNCj4gKwkJZ290byBmYWlsMTsNCj4gKwl9IGVsc2Ug ew0KPiArCQlkZXZfaW5mbygmY2xpZW50cC0+ZGV2LCAiaTJjIGRldmljZSBtYXRjaCBpbiBwcm9i ZVxuIik7DQo+ICsJfQ0KPiArCXJldCA9IGkyY19zbWJ1c193cml0ZV9ieXRlKGNsaWVudHAsIChU U0wyNThYX0NNRF9SRUcgfCBUU0wyNThYX0NOVFJMKSk7DQo+ICsJaWYgKHJldCA8IDApIHsNCj4g KwkJZGV2X2VycigmY2xpZW50cC0+ZGV2LCAiaTJjX3NtYnVzX3dyaXRlX2J5dGUoKSB0byBjbWQg cmVnICINCj4gKwkJCSJmYWlsZWQgaW4gdGFvc19wcm9iZSgpLCBlcnIgPSAlZFxuIiwgcmV0KTsN Cj4gKwkJZ290byBmYWlsMTsNCj4gKwl9DQo+ICsJY2hpcC0+dmFsaWQgPSAwOw0KPiArDQo+ICsJ Y2hpcC0+aWlvX2RldiA9IGlpb19hbGxvY2F0ZV9kZXZpY2UoKTsNCj4gKwlpZiAoIWNoaXAtPmlp b19kZXYpIHsNCj4gKwkJcmV0ID0gLUVOT01FTTsNCj4gKwkJZGV2X2VycigmY2xpZW50cC0+ZGV2 LCAiaWlvIGFsbG9jYXRpb24gZmFpbGVkXG4iKTsNCj4gKwkJZ290byBmYWlsMTsNCj4gKwl9DQo+ ICsNCj4gKwljaGlwLT5paW9fZGV2LT5hdHRycyA9ICZ0c2wyNTh4X2F0dHJpYnV0ZV9ncm91cDsN Cj4gKwljaGlwLT5paW9fZGV2LT5kZXYucGFyZW50ID0gJmNsaWVudHAtPmRldjsNCj4gKwljaGlw LT5paW9fZGV2LT5kZXZfZGF0YSA9ICh2b2lkICopKGNoaXApOw0KPiArCWNoaXAtPmlpb19kZXYt PmRyaXZlcl9tb2R1bGUgPSBUSElTX01PRFVMRTsNCj4gKwljaGlwLT5paW9fZGV2LT5tb2RlcyA9 IElORElPX0RJUkVDVF9NT0RFOw0KPiArCXJldCA9IGlpb19kZXZpY2VfcmVnaXN0ZXIoY2hpcC0+ aWlvX2Rldik7DQo+ICsJaWYgKHJldCkgew0KPiArCQlkZXZfZXJyKCZjbGllbnRwLT5kZXYsICJp aW8gcmVnaXN0cmF0aW9uIGZhaWxlZFxuIik7DQo+ICsJCWdvdG8gZmFpbDE7DQo+ICsJfQ0KPiAr DQo+ICsJLyogTG9hZCB1cCB0aGUgVjIgZGVmYXVsdHMgKHRoZXNlIGFyZSBoYXJkIGNvZGVkIGRl ZmF1bHRzIGZvciBub3cpICovDQo+ICsJdGFvc19kZWZhdWx0cyhjaGlwKTsNCj4gKw0KPiArCS8q IE1ha2Ugc3VyZSB0aGUgY2hpcCBpcyBvbiAqLw0KPiArCXRhb3NfY2hpcF9vbihjbGllbnRwKTsN Cj4gKw0KPiArCWRldl9pbmZvKCZjbGllbnRwLT5kZXYsICJMaWdodCBzZW5zb3IgZm91bmQuXG4i KTsNCj4gKwlyZXR1cm4gMDsNCj4gKw0KPiArZmFpbDE6DQo+ICsJa2ZyZWUoY2hpcCk7DQo+ICsN Cj4gKwlyZXR1cm4gcmV0Ow0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW50IF9fZGV2ZXhpdCB0YW9z X3JlbW92ZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50KSB7DQo+ICsJc3RydWN0IHRzbDI1OHhf Y2hpcCAqY2hpcCA9IGkyY19nZXRfY2xpZW50ZGF0YShjbGllbnQpOw0KPiArDQo+ICsJaWlvX2Rl dmljZV91bnJlZ2lzdGVyKGNoaXAtPmlpb19kZXYpOw0KPiArDQo+ICsJa2ZyZWUoY2hpcCk7DQo+ ICsJcmV0dXJuIDA7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBzdHJ1Y3QgaTJjX2RldmljZV9pZCB0 YW9zX2lkdGFibGVbXSA9IHsNCj4gKwl7IERFVklDRV9JRCwgMCB9LA0KPiArCXt9DQpQbGVhc2Ug Y2FuIHdlIGhhdmUgYW4gZXhwbGljaXQgbGlzdCBpZiBJRCdzIGhlcmUuICBJZiBhIHBlcnNvbiBo YXMgYSB0c2wyNTgwIHRoZW4gdGhleSdsbCB3YW50IHRvIHNheSB0aGF0IGluIHRoZWlyIGJvYXJk IGZpbGUuIC0gRE9ORSBJTkNMVURFUyBBTEwgRkFNSUxZIERFVklDRVMNCg0KT24gdGhhdCBub3Rl LCBJIHNraXBwZWQgdGhpcyBvcmlnaW5hbGx5IGFzIHRoZXJlIHdlcmUgYmlnZ2VyIGZpc2ggdG8g ZnJ5LCBidXQgY2FuIHdlIGJlIHN1cmUgdGhhdCB0aGVyZSB3aWxsIG5ldmVyIGJlIGEgdmFsdWUg b2YgeCB0aGF0IHRoaXMgZHJpdmVyIHdvbid0IHdvcmsgZm9yPyAgSWYgbm90LCBwbGVhc2UgZm9s bG93IGNvbnZlbnRpb24gYW5kIHBpY2sgeW91ciBmYXZvdXJpdGUgcGFydCBudW1iZXIgZnJvbSB0 aGUgcmFuZ2UgYW5kIHJlcGxhY2UgYWxsIHgncyBpbiB0aGUgZHJpdmVyIGFwcHJvcHJpYXRlbHku ICBUb28gbWFueSBwYXJ0IG1hbnVmYWN0dXJlcnMgaGF2ZSByZWFsbHkgd2VpcmQgbmFtaW5nIHNj aGVtZXMgdGhhdCB0ZW5kIHRvIGJyZWFrIHdpbGQgY2FyZHMgbGlrZSB0aGlzIQ0KDQpET05FIC0g RFJJVkVSIE5BTUUgVE8gVFNMMjU4MyAtIEFMU08gU1VQUE9SVFMgMjU4MCw4MSAtIEFTIFNUQVRF RCBJTiBLQ09ORklHIEhFTFANCg0KDQo+ICt9Ow0KPiArTU9EVUxFX0RFVklDRV9UQUJMRShpMmMs IHRhb3NfaWR0YWJsZSk7DQo+ICsNCj4gKy8qIERyaXZlciBkZWZpbml0aW9uICovDQo+ICtzdGF0 aWMgc3RydWN0IGkyY19kcml2ZXIgdGFvc19kcml2ZXIgPSB7DQo+ICsJLmRyaXZlciA9IHsNCj4g KwkJLm5hbWUgPSAidHNsMjU4eCIsDQo+ICsJfSwNCj4gKwkuaWRfdGFibGUgPSB0YW9zX2lkdGFi bGUsDQo+ICsJLnByb2JlID0gdGFvc19wcm9iZSwNCj4gKwkucmVtb3ZlID0gX19kZXZleGl0X3Ao dGFvc19yZW1vdmUpLA0KPiArfTsNCj4gKw0KPiArc3RhdGljIGludCBfX2luaXQgdGFvc19pbml0 KHZvaWQpDQo+ICt7DQo+ICsJcmV0dXJuIGkyY19hZGRfZHJpdmVyKCZ0YW9zX2RyaXZlcik7IH0N Cj4gKw0KPiArc3RhdGljIHZvaWQgX19leGl0IHRhb3NfZXhpdCh2b2lkKQ0KPiArew0KPiArCWky Y19kZWxfZHJpdmVyKCZ0YW9zX2RyaXZlcik7DQo+ICt9DQo+ICsNCj4gK21vZHVsZV9pbml0KHRh b3NfaW5pdCk7DQo+ICttb2R1bGVfZXhpdCh0YW9zX2V4aXQpOw0KPiArDQo+ICtNT0RVTEVfQVVU SE9SKCJKLiBBdWd1c3QgQnJlbm5lcjxqYnJlbm5lckB0YW9zaW5jLmNvbT4iKTsgDQo+ICtNT0RV TEVfREVTQ1JJUFRJT04oIlRBT1MgdHNsMjU4eCBhbWJpZW50IGxpZ2h0IHNlbnNvciBkcml2ZXIi KTsgDQo+ICtNT0RVTEVfTElDRU5TRSgiR1BMIik7DQo+ICsNCg0K ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 2.6.38-rc7]TAOS 258x: Device Driver @ 2011-03-14 19:45 Jon Brenner 2011-03-21 19:07 ` Jonathan Cameron 0 siblings, 1 reply; 10+ messages in thread From: Jon Brenner @ 2011-03-14 19:45 UTC (permalink / raw) To: Jonathan Cameron; +Cc: linux-iio, Linux Kernel From: Jon Brenner <jbrenner@taosinc.com> Support for TAOS tsl2580/01/03 ALS devices. Uses sysfs/iio methods. Signed-off-by: Jon August Brenner <jbrenner@taosinc.com> --- drivers/staging/iio/Documentation/sysfs-bus-iio | 6 + .../staging/iio/Documentation/sysfs-bus-iio-light | 7 + drivers/staging/iio/light/Kconfig | 9 + drivers/staging/iio/light/Makefile | 1 + drivers/staging/iio/light/tsl2583.c | 943 ++++++++++++++++++++ 5 files changed, 966 insertions(+), 0 deletions(-) diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio index 2dde97d..6a86ad2 100644 --- a/drivers/staging/iio/Documentation/sysfs-bus-iio +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio @@ -6,6 +6,12 @@ Description: Corresponds to a grouping of sensor channels. X is the IIO index of the device. +What: /sys/bus/iio/devices/device[n]/power_state +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + This property gets/sets the device power state. + What: /sys/bus/iio/devices/triggerX KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/drivers/staging/iio/Documentation/sysfs-bus-iio-light index 5d84856..b59cdb4 100644 --- a/drivers/staging/iio/Documentation/sysfs-bus-iio-light +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light @@ -62,3 +62,10 @@ Description: sensing mode. This value should be the output from a reading and if expressed in SI units, should include _input. If this value is not in SI units, then it should include _raw. + +What: /sys/bus/iio/devices/device[n]/lux_table +KernelVersion: 2.6.37 +Contact: linux-iio@vger.kernel.org +Description: + This property gets/sets the table of coefficients + used in calculating illuminance in lux. diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig index 36d8bbe..a295e82 100644 --- a/drivers/staging/iio/light/Kconfig +++ b/drivers/staging/iio/light/Kconfig @@ -13,6 +13,15 @@ config SENSORS_TSL2563 This driver can also be built as a module. If so, the module will be called tsl2563. +config SENSORS_TSL2583 + tristate "TAOS TSL2580, TSL2581, and TSL2583 light-to-digital converters" + depends on I2C + help + Y = in kernel. + M = as module. + Provides support for the TAOS tsl2580, tsl2581, and tsl2583 devices. + Access ALS data via iio, sysfs. + config SENSORS_ISL29018 tristate "ISL 29018 light and proximity sensor" depends on I2C diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile index 9142c0e..9d13b8d 100644 --- a/drivers/staging/iio/light/Makefile +++ b/drivers/staging/iio/light/Makefile @@ -3,4 +3,5 @@ # obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o +obj-$(CONFIG_SENSORS_TSL2583) += tsl2583.o obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c new file mode 100644 index 0000000..96e4487 --- /dev/null +++ b/drivers/staging/iio/light/tsl2583.c @@ -0,0 +1,943 @@ +/* + * Device driver for monitoring ambient light intensity (lux) + * within the TAOS tsl258x family of devices (tsl2580, tsl2581). + * + * Copyright (c) 2011, TAOS Corporation. + * + * 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. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/mutex.h> +#include "../iio.h" + + +#define MAX_DEVICE_REGS 32 + +/* Triton register offsets */ +#define TAOS_REG_MAX 8 + +/* Device Registers and Masks */ +#define TSL258X_CNTRL 0x00 +#define TSL258X_ALS_TIME 0X01 +#define TSL258X_INTERRUPT 0x02 +#define TSL258X_GAIN 0x07 +#define TSL258X_REVID 0x11 +#define TSL258X_CHIPID 0x12 +#define TSL258X_ALS_CHAN0LO 0x14 +#define TSL258X_ALS_CHAN0HI 0x15 +#define TSL258X_ALS_CHAN1LO 0x16 +#define TSL258X_ALS_CHAN1HI 0x17 +#define TSL258X_TMR_LO 0x18 +#define TSL258X_TMR_HI 0x19 + +/* tsl2583 cmd reg masks */ +#define TSL258X_CMD_REG 0x80 +#define TSL258X_CMD_SPL_FN 0x60 +#define TSL258X_CMD_ALS_INT_CLR 0X01 + +/* tsl2583 cntrl reg masks */ +#define TSL258X_CNTL_ADC_ENBL 0x02 +#define TSL258X_CNTL_PWR_ON 0x01 + +/* tsl2583 status reg masks */ +#define TSL258X_STA_ADC_VALID 0x01 +#define TSL258X_STA_ADC_INTR 0x10 + +/* Lux calculation constants */ +#define LUX_CALC_OVER_FLOW 65535 + +enum { + TAOS_CHIP_UNKNOWN = 0, TAOS_CHIP_WORKING = 1, TAOS_CHIP_SLEEP = 2 +} TAOS_CHIP_WORKING_STATUS; + +/* Per-device data */ +struct taos_als_info { + u16 als_ch0; + u16 als_ch1; + u16 lux; +}; + +struct taos_settings { + int als_time; + int als_gain; + int als_gain_trim; + int als_cal_target; +}; + +struct tsl2583_chip { + struct mutex als_mutex; + struct i2c_client *client; + struct iio_dev *iio_dev; + struct delayed_work update_lux; + unsigned int addr; + char taos_id; + char valid; + unsigned long last_updated; + struct taos_als_info als_cur_info; + struct taos_settings taos_settings; + int als_time_scale; + int als_saturation; + int taos_chip_status; + u8 taos_config[8]; +}; + +static int taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, + unsigned int len); +static int taos_i2c_write_command(struct i2c_client *client, u8 reg); + +/* + * Initial values for device - this values can/will be changed by driver. + * and applications as needed. + * These values are dynamic. + */ +static const u8 taos_config[8] = { + 0x00, 0xee, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x00 +}; /* cntrl atime intC Athl0 Athl1 Athh0 Athh1 gain */ + +struct taos_lux { + unsigned int ratio; + unsigned int ch0; + unsigned int ch1; +}; + +/* This structure is intentionally large to accommodate updates via sysfs. */ +/* Sized to 11 = max 10 segments + 1 termination segment */ +/* Assumption is is one and only one type of glass used */ +struct taos_lux taos_device_lux[11] = { + { 9830, 8520, 15729 }, + { 12452, 10807, 23344 }, + { 14746, 6383, 11705 }, + { 17695, 4063, 6554 }, +}; + +struct taos_lux taos_lux; + +struct gainadj { + s16 ch0; + s16 ch1; +}; + +/* Index = (0 - 3) Used to validate the gain selection index */ +static const struct gainadj gainadj[] = { + { 1, 1 }, + { 8, 8 }, + { 16, 16 }, + { 107, 115 } +}; + +/* + * Provides initial operational parameter defaults. + * These defaults may be changed through the device's sysfs files. + */ +static void taos_defaults(struct tsl2583_chip *chip) +{ + /* Operational parameters */ + chip->taos_settings.als_time = 450; + /* must be a multiple of 50mS */ + chip->taos_settings.als_gain = 2; + /* this is actually an index into the gain table */ + /* assume clear glass as default */ + chip->taos_settings.als_gain_trim = 1000; + /* default gain trim to account for aperture effects */ + chip->taos_settings.als_cal_target = 130; + /* Known external ALS reading used for calibration */ +} + +/* + * Read a number of bytes starting at register (reg) location. + * Return 0, or i2c_smbus_write_byte ERROR code. + */ +static int +taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, unsigned int len) +{ + int ret; + int i; + + for (i = 0; i < len; i++) { + /* select register to write */ + ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | reg)); + if (ret < 0) { + dev_err(&client->dev, "taos_i2c_read failed to write" + " register %x\n", reg); + return ret; + } + /* read the data */ + *val = i2c_smbus_read_byte(client); + val++; + reg++; + } + return 0; +} + +/* + * This function is used to send a command to device command/control register + * All bytes sent using this command have their MSBit set - it's a command! + * Return 0, or i2c_smbus_write_byte error code. + */ +static int taos_i2c_write_command(struct i2c_client *client, u8 reg) +{ + int ret; + + /* write the data */ + ret = i2c_smbus_write_byte(client, (reg |= TSL258X_CMD_REG)); + if (ret < 0) { + dev_err(&client->dev, "FAILED: i2c_smbus_write_byte\n"); + return ret; + } + return 0; +} + +/* + * Reads and calculates current lux value. + * The raw ch0 and ch1 values of the ambient light sensed in the last + * integration cycle are read from the device. + * Time scale factor array values are adjusted based on the integration time. + * The raw values are multiplied by a scale factor, and device gain is obtained + * using gain index. Limit checks are done next, then the ratio of a multiple + * of ch1 value, to the ch0 value, is calculated. The array taos_device_lux[] + * declared above is then scanned to find the first ratio value that is just + * above the ratio we just calculated. The ch0 and ch1 multiplier constants in + * the array are then used along with the time scale factor array values, to + * calculate the lux. + */ +static int taos_get_lux(struct i2c_client *client) +{ + u32 ch0, ch1; /* separated ch0/ch1 data from device */ + u32 lux; /* raw lux calculated from device data */ + u32 ratio; + u8 buf[5]; + struct taos_lux *p; + struct tsl2583_chip *chip = i2c_get_clientdata(client); + int i, ret; + u32 ch0lux = 0; + u32 ch1lux = 0; + + if (mutex_trylock(&chip->als_mutex) == 0) { + dev_info(&client->dev, "taos_get_lux device is busy\n"); + return chip->als_cur_info.lux; /* busy, so return LAST VALUE */ + } + + if (chip->taos_chip_status != TAOS_CHIP_WORKING) { + /* device is not enabled */ + dev_err(&client->dev, "taos_get_lux device is not enabled\n"); + ret = -EBUSY ; + goto out_unlock; + } + + ret = taos_i2c_read(client, (TSL258X_CMD_REG), &buf[0], 1); + if (ret < 0) { + dev_err(&client->dev, "taos_get_lux failed to read CMD_REG\n"); + goto out_unlock; + } + /* is data new & valid */ + if (!(buf[0] & TSL258X_STA_ADC_INTR)) { + dev_err(&client->dev, "taos_get_lux data not valid\n"); + ret = chip->als_cur_info.lux; /* return LAST VALUE */ + goto out_unlock; + } + + for (i = 0; i < 4; i++) { + int reg = TSL258X_CMD_REG | (TSL258X_ALS_CHAN0LO + i); + ret = taos_i2c_read(client, reg, &buf[i], 1); + if (ret < 0) { + dev_err(&client->dev, "taos_get_lux failed to read" + " register %x\n", reg); + goto out_unlock; + } + } + + /* clear status, really interrupt status (interrupts are off), but + * we use the bit anyway */ + ret = taos_i2c_write_command(client, + TSL258X_CMD_REG | TSL258X_CMD_SPL_FN | TSL258X_CMD_ALS_INT_CLR); + if (ret < 0) { + dev_err(&client->dev, + "taos_i2c_write_command failed in taos_get_lux, err = %d\n", + ret); + goto out_unlock; /* have no data, so return failure */ + } + + /* extract ALS/lux data */ + ch0 = (buf[1] << 8) | buf[0]; + ch1 = (buf[3] << 8) | buf[2]; + + chip->als_cur_info.als_ch0 = ch0; + chip->als_cur_info.als_ch1 = ch1; + + if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) + goto return_max; + + if (ch0 == 0) { + /* have no data, so return LAST VALUE */ + ret = chip->als_cur_info.lux = 0; + goto out_unlock; + } + /* calculate ratio */ + ratio = (ch1 << 15) / ch0; + /* convert to unscaled lux using the pointer to the table */ + for (p = (struct taos_lux *) taos_device_lux; + p->ratio != 0 && p->ratio < ratio; p++) + ; + + if (p->ratio == 0) { + lux = 0; + } else { + ch0lux = ((ch0 * p->ch0) + + (gainadj[chip->taos_settings.als_gain].ch0 >> 1)) + / gainadj[chip->taos_settings.als_gain].ch0; + ch1lux = ((ch1 * p->ch1) + + (gainadj[chip->taos_settings.als_gain].ch1 >> 1)) + / gainadj[chip->taos_settings.als_gain].ch1; + lux = ch0lux - ch1lux; + } + + /* note: lux is 31 bit max at this point */ + if (ch1lux > ch0lux) { + dev_dbg(&client->dev, "No Data - Return last value\n"); + ret = chip->als_cur_info.lux = 0; + goto out_unlock; + } + + /* adjust for active time scale */ + if (chip->als_time_scale == 0) + lux = 0; + else + lux = (lux + (chip->als_time_scale >> 1)) / + chip->als_time_scale; + + /* adjust for active gain scale */ + lux >>= 13; /* tables have factor of 8192 builtin for accuracy */ + lux = (lux * chip->taos_settings.als_gain_trim + 500) / 1000; + if (lux > LUX_CALC_OVER_FLOW) { /* check for overflow */ +return_max: + lux = LUX_CALC_OVER_FLOW; + } + + /* Update the structure with the latest VALID lux. */ + chip->als_cur_info.lux = lux; + ret = lux; + +out_unlock: + mutex_unlock(&chip->als_mutex); + return ret; +} + +/* + * Obtain single reading and calculate the als_gain_trim (later used + * to derive actual lux). + * Return updated gain_trim value. + */ +int taos_als_calibrate(struct i2c_client *client) +{ + struct tsl2583_chip *chip = i2c_get_clientdata(client); + u8 reg_val; + unsigned int gain_trim_val; + int ret; + int lux_val; + + ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | TSL258X_CNTRL)); + if (ret < 0) { + dev_err(&client->dev, + "taos_als_calibrate failed to reach the CNTRL register, ret=%d\n", + ret); + return ret; + } + + reg_val = i2c_smbus_read_byte(client); + if ((reg_val & (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWR_ON)) + != (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWR_ON)) { + dev_err(&client->dev, + "taos_als_calibrate failed: device not powered on with ADC enabled\n"); + return -ENODATA; + } + + ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | TSL258X_CNTRL)); + if (ret < 0) { + dev_err(&client->dev, + "taos_als_calibrate failed to reach the STATUS register, ret=%d\n", + ret); + return ret; + } + reg_val = i2c_smbus_read_byte(client); + + if ((reg_val & TSL258X_STA_ADC_VALID) != TSL258X_STA_ADC_VALID) { + dev_err(&client->dev, + "taos_als_calibrate failed: STATUS - ADC not valid.\n"); + return -ENODATA; + } + lux_val = taos_get_lux(client); + if (lux_val < 0) { + dev_err(&client->dev, "taos_als_calibrate failed to get lux\n"); + return lux_val; + } + gain_trim_val = (unsigned int) (((chip->taos_settings.als_cal_target) + * chip->taos_settings.als_gain_trim) / lux_val); + + dev_info(&client->dev, "taos_settings.als_cal_target = %d\n" + "taos_settings.als_gain_trim = %d\nlux_val = %d\n", + chip->taos_settings.als_cal_target, + chip->taos_settings.als_gain_trim, + lux_val); + + if ((gain_trim_val < 250) || (gain_trim_val > 4000)) { + dev_err(&client->dev, + "taos_als_calibrate failed: trim_val of %d is out of range\n", + gain_trim_val); + return -ENODATA; + } + chip->taos_settings.als_gain_trim = (int) gain_trim_val; + + return (int) gain_trim_val; +} + +/* + * Turn the device on. + * Configuration must be set before calling this function. + */ +static int taos_chip_on(struct i2c_client *client) +{ + int i; + int ret = 0; + u8 *uP; + u8 utmp; + int als_count; + int als_time; + struct tsl2583_chip *chip = i2c_get_clientdata(client); + + /* and make sure we're not already on */ + if (chip->taos_chip_status == TAOS_CHIP_WORKING) { + /* if forcing a register update - turn off, then on */ + dev_info(&client->dev, "device is already enabled\n"); + return -1; + } + + /* determine als integration regster */ + als_count = (chip->taos_settings.als_time * 100 + 135) / 270; + if (als_count == 0) + als_count = 1; /* ensure at least one cycle */ + + /* convert back to time (encompasses overrides) */ + als_time = (als_count * 27 + 5) / 10; + chip->taos_config[TSL258X_ALS_TIME] = 256 - als_count; + + /* Set the gain based on taos_settings struct */ + chip->taos_config[TSL258X_GAIN] = chip->taos_settings.als_gain; + + /* set chip struct re scaling and saturation */ + chip->als_saturation = als_count * 922; /* 90% of full scale */ + chip->als_time_scale = (als_time + 25) / 50; + + /* SKATE Specific power-on / adc enable sequence + * Power on the device 1st. */ + utmp = TSL258X_CNTL_PWR_ON; + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG | TSL258X_CNTRL, + utmp); + if (ret < 0) { + dev_err(&client->dev, "taos_chip_on failed on CNTRL reg.\n"); + return -1; + } + + /* Use the following shadow copy for our delay before enabling ADC. + * Write all the registers. */ + for (i = 0, uP = chip->taos_config; i < TAOS_REG_MAX; i++) { + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG + i, + *uP++); + if (ret < 0) { + dev_err(&client->dev, + "taos_chip_on failed on reg %d.\n", i); + return -1; + } + } + + mdelay(3); + /* NOW enable the ADC + * initialize the desired mode of operation */ + utmp = TSL258X_CNTL_PWR_ON | TSL258X_CNTL_ADC_ENBL; + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG | TSL258X_CNTRL, + utmp); + if (ret < 0) { + dev_err(&client->dev, "taos_chip_on failed on 2nd CTRL reg.\n"); + return -1; + } + chip->taos_chip_status = TAOS_CHIP_WORKING; + return ret; +} + +/* Turn the device OFF. */ +static int taos_chip_off(struct i2c_client *client) +{ + struct tsl2583_chip *chip = i2c_get_clientdata(client); + int ret; + u8 utmp; + + /* turn device off */ + chip->taos_chip_status = TAOS_CHIP_SLEEP; + utmp = 0x00; + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG | TSL258X_CNTRL, + utmp); + return ret; +} + +/* Sysfs Interface Functions */ +static ssize_t taos_device_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + + return sprintf(buf, "%s\n", chip->client->name); +} + +static ssize_t taos_power_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + + return sprintf(buf, "%d\n", chip->taos_chip_status); +} + +static ssize_t taos_power_state_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + unsigned long value; + + if (strict_strtoul(buf, 0, &value)) + return -EINVAL; + + if (value == 0) + taos_chip_off(chip->client); + else + taos_chip_on(chip->client); + + return len; +} + +static ssize_t taos_gain_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + + return sprintf(buf, "%d\n", chip->taos_settings.als_gain); +} + +static ssize_t taos_gain_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + unsigned long value; + if (strict_strtoul(buf, 0, &value)) + return -EINVAL; + + if (value > 3) { + dev_err(dev, "Invalid Gain Index: Enter 0-3\n"); + return -1; + } else { + chip->taos_settings.als_gain = value; + } + return len; +} + +static ssize_t taos_gain_available_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", "0 1 2 3"); +} + +static ssize_t taos_als_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + + return sprintf(buf, "%d\n", chip->taos_settings.als_time); +} + +static ssize_t taos_als_time_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + unsigned long value; + + if (strict_strtoul(buf, 0, &value)) + return -EINVAL; + + if ((value < 50) || (value > 650)) + return -EINVAL; + + if (value % 50) + return -EINVAL; + + chip->taos_settings.als_time = value; + + return len; +} + +static ssize_t taos_als_time_available_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", "50 100 150 200 250 300 350 400 450 500 550 600 650"); +} + +static ssize_t taos_als_trim_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + + return sprintf(buf, "%d\n", chip->taos_settings.als_gain_trim); +} + +static ssize_t taos_als_trim_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + unsigned long value; + + if (strict_strtoul(buf, 0, &value)) + return -EINVAL; + + if (value) + chip->taos_settings.als_gain_trim = value; + + return len; +} + +static ssize_t taos_als_cal_target_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + + return sprintf(buf, "%d\n", chip->taos_settings.als_cal_target); +} + +static ssize_t taos_als_cal_target_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + unsigned long value; + + if (strict_strtoul(buf, 0, &value)) + return -EINVAL; + + if (value) + chip->taos_settings.als_cal_target = value; + + return len; +} + +static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + int lux; + + lux = taos_get_lux(chip->client); + + return sprintf(buf, "%d\n", lux); +} + +static ssize_t taos_do_calibrate(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + unsigned long value; + + if (strict_strtoul(buf, 0, &value)) + return -EINVAL; + + if (value == 1) + taos_als_calibrate(chip->client); + + return len; +} + +static ssize_t taos_luxtable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i; + int offset = 0; + + for (i = 0; i < ARRAY_SIZE(taos_device_lux); i++) { + offset += sprintf(buf + offset, "%d,%d,%d,", + taos_device_lux[i].ratio, + taos_device_lux[i].ch0, + taos_device_lux[i].ch1); + if (taos_device_lux[i].ratio == 0) { + /* We just printed the first "0" entry. + * Now get rid of the extra "," and break. */ + offset--; + break; + } + } + + offset += sprintf(buf + offset, "\n"); + return offset; +} + +static ssize_t taos_luxtable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct tsl2583_chip *chip = indio_dev->dev_data; + int value[ARRAY_SIZE(taos_device_lux)]; + int n; + + get_options(buf, ARRAY_SIZE(value), value); + + /* We now have an array of ints starting at value[1], and + * enumerated by value[0]. + * We expect each group of three ints is one table entry, + * and the last table entry is all 0. + */ + n = value[0]; + if ((n % 3) || n < 6 || n > (ARRAY_SIZE(taos_device_lux) - 3)) { + dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n); + return -EINVAL; + } + if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) { + dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n); + return -EINVAL; + } + + if (chip->taos_chip_status == TAOS_CHIP_WORKING) + taos_chip_off(chip->client); + + /* Zero out the table */ + memset(taos_device_lux, 0, sizeof(taos_device_lux)); + memcpy(taos_device_lux, &value[1], (value[0] * 4)); + + taos_chip_on(chip->client); + + return len; +} + +static DEVICE_ATTR(name, S_IRUGO, taos_device_id, NULL); +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, + taos_power_state_show, taos_power_state_store); + +static DEVICE_ATTR(illuminance0_calibscale, S_IRUGO | S_IWUSR, + taos_gain_show, taos_gain_store); +static DEVICE_ATTR(illuminance0_calibscale_available, S_IRUGO, + taos_gain_available_show, NULL); + +static DEVICE_ATTR(sampling_frequency, S_IRUGO | S_IWUSR, + taos_als_time_show, taos_als_time_store); +static DEVICE_ATTR(sampling_frequency_available, S_IRUGO, + taos_als_time_available_show, NULL); + +static DEVICE_ATTR(scale, S_IRUGO | S_IWUSR, + taos_als_trim_show, taos_als_trim_store); + +static DEVICE_ATTR(illuminance0_target, S_IRUGO | S_IWUSR, + taos_als_cal_target_show, taos_als_cal_target_store); + +static DEVICE_ATTR(illuminance0_input, S_IRUGO, taos_lux_show, NULL); +static DEVICE_ATTR(calibrate, S_IWUSR, NULL, taos_do_calibrate); +static DEVICE_ATTR(lux_table, S_IRUGO | S_IWUSR, + taos_luxtable_show, taos_luxtable_store); + +static struct attribute *sysfs_attrs_ctrl[] = { + &dev_attr_name.attr, + &dev_attr_power_state.attr, + &dev_attr_illuminance0_calibscale.attr, + &dev_attr_illuminance0_calibscale_available.attr, + &dev_attr_sampling_frequency.attr, + &dev_attr_sampling_frequency_available.attr, + &dev_attr_scale.attr, + &dev_attr_illuminance0_target.attr, + &dev_attr_illuminance0_input.attr, + &dev_attr_calibrate.attr, + &dev_attr_lux_table.attr, + NULL +}; + +static struct attribute_group tsl2583_attribute_group = { + .attrs = sysfs_attrs_ctrl, +}; + +/* Use the default register values to identify the Taos device */ +static int taos_skate_device(unsigned char *bufp) +{ + if (((bufp[TSL258X_CHIPID] & 0xf0) == 0x90)) + /* tsl2583 */ + return 1; + /* else unknown */ + return 0; +} + +/* + * Client probe function - When a valid device is found, the driver's device + * data structure is updated, and initialization completes successfully. + */ +static int __devinit taos_probe(struct i2c_client *clientp, + const struct i2c_device_id *idp) +{ + int i, ret = 0; + unsigned char buf[MAX_DEVICE_REGS]; + static struct tsl2583_chip *chip; + + if (!i2c_check_functionality(clientp->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&clientp->dev, + "taos_probe() - i2c smbus byte data " + "functions unsupported\n"); + return -EOPNOTSUPP; + } + if (!i2c_check_functionality(clientp->adapter, + I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&clientp->dev, + "taos_probe() - i2c smbus word data " + "functions unsupported\n"); + } + if (!i2c_check_functionality(clientp->adapter, + I2C_FUNC_SMBUS_BLOCK_DATA)) { + dev_err(&clientp->dev, + "taos_probe() - i2c smbus block data " + "functions unsupported\n"); + } + + chip = kzalloc(sizeof(struct tsl2583_chip), GFP_KERNEL); + if (!chip) { + dev_err(&clientp->dev, "taos_device_drvr: kmalloc for " + "struct tsl2583_chip failed in taos_probe()\n"); + return -ENOMEM; + } + + chip->client = clientp; + i2c_set_clientdata(clientp, chip); + + mutex_init(&chip->als_mutex); + chip->taos_chip_status = TAOS_CHIP_UNKNOWN; /* uninitialized to start */ + memcpy(chip->taos_config, taos_config, sizeof(chip->taos_config)); + + for (i = 0; i < MAX_DEVICE_REGS; i++) { + ret = i2c_smbus_write_byte(clientp, + (TSL258X_CMD_REG | (TSL258X_CNTRL + i))); + if (ret < 0) { + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd " + "reg failed in taos_probe(), err = %d\n", ret); + goto fail1; + } + buf[i] = i2c_smbus_read_byte(clientp); + } + if (!taos_skate_device(buf)) { + dev_info(&clientp->dev, "i2c device found but does not match " + "expected id in taos_probe()\n"); + goto fail1; + } else { + dev_info(&clientp->dev, "i2c device match in probe\n"); + } + ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | TSL258X_CNTRL)); + if (ret < 0) { + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg " + "failed in taos_probe(), err = %d\n", ret); + goto fail1; + } + chip->valid = 0; + + chip->iio_dev = iio_allocate_device(); + if (!chip->iio_dev) { + ret = -ENOMEM; + dev_err(&clientp->dev, "iio allocation failed\n"); + goto fail1; + } + + chip->iio_dev->attrs = &tsl2583_attribute_group; + chip->iio_dev->dev.parent = &clientp->dev; + chip->iio_dev->dev_data = (void *)(chip); + chip->iio_dev->driver_module = THIS_MODULE; + chip->iio_dev->modes = INDIO_DIRECT_MODE; + ret = iio_device_register(chip->iio_dev); + if (ret) { + dev_err(&clientp->dev, "iio registration failed\n"); + goto fail1; + } + + /* Load up the V2 defaults (these are hard coded defaults for now) */ + taos_defaults(chip); + + /* Make sure the chip is on */ + taos_chip_on(clientp); + + dev_info(&clientp->dev, "Light sensor found.\n"); + return 0; + +fail1: + kfree(chip); + + return ret; +} + +static int __devexit taos_remove(struct i2c_client *client) +{ + struct tsl2583_chip *chip = i2c_get_clientdata(client); + + iio_device_unregister(chip->iio_dev); + + kfree(chip); + return 0; +} + +static struct i2c_device_id taos_idtable[] = { + { "tsl2580", 0 }, + { "tsl2581", 1 }, + { "tsl2583", 2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, taos_idtable); + +/* Driver definition */ +static struct i2c_driver taos_driver = { + .driver = { + .name = "tsl2583", + }, + .id_table = taos_idtable, + .probe = taos_probe, + .remove = __devexit_p(taos_remove), +}; + +static int __init taos_init(void) +{ + return i2c_add_driver(&taos_driver); +} + +static void __exit taos_exit(void) +{ + i2c_del_driver(&taos_driver); +} + +module_init(taos_init); +module_exit(taos_exit); + +MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>"); +MODULE_DESCRIPTION("TAOS tsl2583 ambient light sensor driver"); +MODULE_LICENSE("GPL"); + -- 1.7.0.4 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver 2011-03-14 19:45 Jon Brenner @ 2011-03-21 19:07 ` Jonathan Cameron 2011-03-23 1:07 ` Jon Brenner 0 siblings, 1 reply; 10+ messages in thread From: Jonathan Cameron @ 2011-03-21 19:07 UTC (permalink / raw) To: Jon Brenner; +Cc: linux-iio, Linux Kernel On 03/14/11 19:45, Jon Brenner wrote: > From: Jon Brenner <jbrenner@taosinc.com> > > Support for TAOS tsl2580/01/03 ALS devices. > Uses sysfs/iio methods. Hi Jon, As I pm'd you the other day, please remember to make version of patch clear in title, and include details of what has changed since previous version. The 'scale' attribute is a problem. I've suggested one possible solution but I'm open to others. It ought to be handled in a generalizable way but isn't currently. Please document the _target and calibrate attributes in part specific documentation file. Otherwise, various small points inline. Jonathan > > Signed-off-by: Jon August Brenner <jbrenner@taosinc.com> > > --- > drivers/staging/iio/Documentation/sysfs-bus-iio | 6 + > .../staging/iio/Documentation/sysfs-bus-iio-light | 7 + > drivers/staging/iio/light/Kconfig | 9 + > drivers/staging/iio/light/Makefile | 1 + > drivers/staging/iio/light/tsl2583.c | 943 ++++++++++++++++++++ > 5 files changed, 966 insertions(+), 0 deletions(-) > > diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio > index 2dde97d..6a86ad2 100644 > --- a/drivers/staging/iio/Documentation/sysfs-bus-iio > +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio > @@ -6,6 +6,12 @@ Description: > Corresponds to a grouping of sensor channels. X is the IIO > index of the device. > > +What: /sys/bus/iio/devices/device[n]/power_state > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets the device power state. Where the options are? There is some on going debate about how best to handle explicit userspace power control. For now I'll let this go in, but we will need to clean it up in the long run. Basically this is an issue that effects several subsystems and their ought to be one coherent solution. > + > What: /sys/bus/iio/devices/triggerX > KernelVersion: 2.6.35 > Contact: linux-iio@vger.kernel.org > diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/drivers/staging/iio/Documentation/sysfs-bus-iio-light > index 5d84856..b59cdb4 100644 > --- a/drivers/staging/iio/Documentation/sysfs-bus-iio-light > +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light > @@ -62,3 +62,10 @@ Description: > sensing mode. This value should be the output from a reading > and if expressed in SI units, should include _input. If this > value is not in SI units, then it should include _raw. > + > +What: /sys/bus/iio/devices/device[n]/lux_table > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets the table of coefficients > + used in calculating illuminance in lux. This one probably wants to be in a separate file as we only have one user so far and it's not as though a device agnostic userspace program is going to know what to do with it. Put it in syfsf-bus-iio-light-tsl2583 please. > diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig > index 36d8bbe..a295e82 100644 > --- a/drivers/staging/iio/light/Kconfig > +++ b/drivers/staging/iio/light/Kconfig > @@ -13,6 +13,15 @@ config SENSORS_TSL2563 > This driver can also be built as a module. If so, the module > will be called tsl2563. > ouch, how the heck did that SENSORS prefix creep into this file. That's the convention for hwmon, not IIO. Guess I wasn't keeping a close eye on this. Please drop the prefix. We may well introduce an IIO one shortly as part of the move out of staging, but for now no prefix is the norm. > +config SENSORS_TSL2583 > + tristate "TAOS TSL2580, TSL2581, and TSL2583 light-to-digital converters" > + depends on I2C > + help > + Y = in kernel. > + M = as module. > + Provides support for the TAOS tsl2580, tsl2581, and tsl2583 devices. > + Access ALS data via iio, sysfs. > + > config SENSORS_ISL29018 > tristate "ISL 29018 light and proximity sensor" > depends on I2C > diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile > index 9142c0e..9d13b8d 100644 > --- a/drivers/staging/iio/light/Makefile > +++ b/drivers/staging/iio/light/Makefile > @@ -3,4 +3,5 @@ > # > > obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o > +obj-$(CONFIG_SENSORS_TSL2583) += tsl2583.o > obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o > diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c > new file mode 100644 > index 0000000..96e4487 > --- /dev/null > +++ b/drivers/staging/iio/light/tsl2583.c > @@ -0,0 +1,943 @@ > +/* > + * Device driver for monitoring ambient light intensity (lux) > + * within the TAOS tsl258x family of devices (tsl2580, tsl2581). > + * > + * Copyright (c) 2011, TAOS Corporation. > + * > + * 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. > + * > + * 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., > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + */ > + > +#include <linux/kernel.h> > +#include <linux/i2c.h> > +#include <linux/errno.h> > +#include <linux/delay.h> > +#include <linux/string.h> > +#include <linux/mutex.h> > +#include "../iio.h" > + > + Please prefix this with TSL258X to avoid possible namespace clashes in future. > +#define MAX_DEVICE_REGS 32 > + > +/* Triton register offsets */ > +#define TAOS_REG_MAX 8 > + > +/* Device Registers and Masks */ > +#define TSL258X_CNTRL 0x00 > +#define TSL258X_ALS_TIME 0X01 > +#define TSL258X_INTERRUPT 0x02 > +#define TSL258X_GAIN 0x07 > +#define TSL258X_REVID 0x11 > +#define TSL258X_CHIPID 0x12 > +#define TSL258X_ALS_CHAN0LO 0x14 > +#define TSL258X_ALS_CHAN0HI 0x15 > +#define TSL258X_ALS_CHAN1LO 0x16 > +#define TSL258X_ALS_CHAN1HI 0x17 > +#define TSL258X_TMR_LO 0x18 > +#define TSL258X_TMR_HI 0x19 > + > +/* tsl2583 cmd reg masks */ > +#define TSL258X_CMD_REG 0x80 > +#define TSL258X_CMD_SPL_FN 0x60 > +#define TSL258X_CMD_ALS_INT_CLR 0X01 > + > +/* tsl2583 cntrl reg masks */ > +#define TSL258X_CNTL_ADC_ENBL 0x02 > +#define TSL258X_CNTL_PWR_ON 0x01 > + > +/* tsl2583 status reg masks */ > +#define TSL258X_STA_ADC_VALID 0x01 > +#define TSL258X_STA_ADC_INTR 0x10 > + > +/* Lux calculation constants */ Again please prefix. > +#define LUX_CALC_OVER_FLOW 65535 > + Ideally part names in these. You might have another TAOS driver where these are defined differently which will make life confusing! > +enum { > + TAOS_CHIP_UNKNOWN = 0, TAOS_CHIP_WORKING = 1, TAOS_CHIP_SLEEP = 2 > +} TAOS_CHIP_WORKING_STATUS; > + > +/* Per-device data */ > +struct taos_als_info { > + u16 als_ch0; > + u16 als_ch1; > + u16 lux; > +}; > + > +struct taos_settings { > + int als_time; > + int als_gain; > + int als_gain_trim; > + int als_cal_target; > +}; > + > +struct tsl2583_chip { > + struct mutex als_mutex; > + struct i2c_client *client; > + struct iio_dev *iio_dev; unused so remove > + struct delayed_work update_lux; unused. > + unsigned int addr; unused. > + char taos_id; I think this is set to 0 then never checked anywhere? Hence remove > + char valid; never used > + unsigned long last_updated; > + struct taos_als_info als_cur_info; > + struct taos_settings taos_settings; > + int als_time_scale; > + int als_saturation; > + int taos_chip_status; > + u8 taos_config[8]; > +}; > + > +static int taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, > + unsigned int len); > +static int taos_i2c_write_command(struct i2c_client *client, u8 reg); Don't need these definitions. > + > +/* > + * Initial values for device - this values can/will be changed by driver. > + * and applications as needed. > + * These values are dynamic. > + */ > +static const u8 taos_config[8] = { > + 0x00, 0xee, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x00 > +}; /* cntrl atime intC Athl0 Athl1 Athh0 Athh1 gain */ > + > +struct taos_lux { > + unsigned int ratio; > + unsigned int ch0; > + unsigned int ch1; > +}; > + > +/* This structure is intentionally large to accommodate updates via sysfs. */ > +/* Sized to 11 = max 10 segments + 1 termination segment */ > +/* Assumption is is one and only one type of glass used */ > +struct taos_lux taos_device_lux[11] = { > + { 9830, 8520, 15729 }, > + { 12452, 10807, 23344 }, > + { 14746, 6383, 11705 }, > + { 17695, 4063, 6554 }, > +}; > + I don't think this is used? > +struct taos_lux taos_lux; > + > +struct gainadj { > + s16 ch0; > + s16 ch1; > +}; > + > +/* Index = (0 - 3) Used to validate the gain selection index */ > +static const struct gainadj gainadj[] = { > + { 1, 1 }, > + { 8, 8 }, > + { 16, 16 }, > + { 107, 115 } > +}; > + > +/* > + * Provides initial operational parameter defaults. > + * These defaults may be changed through the device's sysfs files. > + */ How about pasing in taos_settings and making all of this func a bit more readable? > +static void taos_defaults(struct tsl2583_chip *chip) > +{ > + /* Operational parameters */ > + chip->taos_settings.als_time = 450; > + /* must be a multiple of 50mS */ > + chip->taos_settings.als_gain = 2; > + /* this is actually an index into the gain table */ > + /* assume clear glass as default */ > + chip->taos_settings.als_gain_trim = 1000; > + /* default gain trim to account for aperture effects */ > + chip->taos_settings.als_cal_target = 130; > + /* Known external ALS reading used for calibration */ > +} > + > +/* > + * Read a number of bytes starting at register (reg) location. > + * Return 0, or i2c_smbus_write_byte ERROR code. > + */ > +static int > +taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, unsigned int len) > +{ > + int ret; > + int i; > + > + for (i = 0; i < len; i++) { > + /* select register to write */ > + ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | reg)); > + if (ret < 0) { > + dev_err(&client->dev, "taos_i2c_read failed to write" > + " register %x\n", reg); > + return ret; > + } > + /* read the data */ > + *val = i2c_smbus_read_byte(client); > + val++; > + reg++; > + } > + return 0; > +} > + > +/* > + * This function is used to send a command to device command/control register > + * All bytes sent using this command have their MSBit set - it's a command! > + * Return 0, or i2c_smbus_write_byte error code. > + */ > +static int taos_i2c_write_command(struct i2c_client *client, u8 reg) > +{ > + int ret; > + > + /* write the data */ Why update reg? reg | TSL258X_CMD_REG. Also this is only used once in the code. I'd just roll this line in directly there and get rid of this wrapper function. > + ret = i2c_smbus_write_byte(client, (reg |= TSL258X_CMD_REG)); > + if (ret < 0) { The error is pretty well reported by the one caller anyway > + dev_err(&client->dev, "FAILED: i2c_smbus_write_byte\n"); > + return ret; > + } Could just return ret as you check this for <0 anyway. > + return 0; > +} > + > +/* > + * Reads and calculates current lux value. > + * The raw ch0 and ch1 values of the ambient light sensed in the last > + * integration cycle are read from the device. > + * Time scale factor array values are adjusted based on the integration time. > + * The raw values are multiplied by a scale factor, and device gain is obtained > + * using gain index. Limit checks are done next, then the ratio of a multiple > + * of ch1 value, to the ch0 value, is calculated. The array taos_device_lux[] > + * declared above is then scanned to find the first ratio value that is just > + * above the ratio we just calculated. The ch0 and ch1 multiplier constants in > + * the array are then used along with the time scale factor array values, to > + * calculate the lux. > + */ > +static int taos_get_lux(struct i2c_client *client) > +{ > + u32 ch0, ch1; /* separated ch0/ch1 data from device */ > + u32 lux; /* raw lux calculated from device data */ > + u32 ratio; > + u8 buf[5]; > + struct taos_lux *p; > + struct tsl2583_chip *chip = i2c_get_clientdata(client); > + int i, ret; > + u32 ch0lux = 0; > + u32 ch1lux = 0; > + > + if (mutex_trylock(&chip->als_mutex) == 0) { > + dev_info(&client->dev, "taos_get_lux device is busy\n"); > + return chip->als_cur_info.lux; /* busy, so return LAST VALUE */ > + } > + > + if (chip->taos_chip_status != TAOS_CHIP_WORKING) { > + /* device is not enabled */ > + dev_err(&client->dev, "taos_get_lux device is not enabled\n"); > + ret = -EBUSY ; > + goto out_unlock; > + } > + > + ret = taos_i2c_read(client, (TSL258X_CMD_REG), &buf[0], 1); > + if (ret < 0) { > + dev_err(&client->dev, "taos_get_lux failed to read CMD_REG\n"); > + goto out_unlock; > + } > + /* is data new & valid */ > + if (!(buf[0] & TSL258X_STA_ADC_INTR)) { > + dev_err(&client->dev, "taos_get_lux data not valid\n"); > + ret = chip->als_cur_info.lux; /* return LAST VALUE */ > + goto out_unlock; > + } > + > + for (i = 0; i < 4; i++) { > + int reg = TSL258X_CMD_REG | (TSL258X_ALS_CHAN0LO + i); > + ret = taos_i2c_read(client, reg, &buf[i], 1); > + if (ret < 0) { > + dev_err(&client->dev, "taos_get_lux failed to read" > + " register %x\n", reg); > + goto out_unlock; > + } > + } > + > + /* clear status, really interrupt status (interrupts are off), but > + * we use the bit anyway */ > + ret = taos_i2c_write_command(client, > + TSL258X_CMD_REG | TSL258X_CMD_SPL_FN | TSL258X_CMD_ALS_INT_CLR); > + if (ret < 0) { > + dev_err(&client->dev, > + "taos_i2c_write_command failed in taos_get_lux, err = %d\n", > + ret); > + goto out_unlock; /* have no data, so return failure */ > + } > + > + /* extract ALS/lux data */ These appear to be endianness convesions. ch0 = le16tocpu(&buf[0])? That way they compile out to a copy if we happen to be on a little endian machine. Also these seem to be explicitly 16 bits, so u16 makes more sense. > + ch0 = (buf[1] << 8) | buf[0]; > + ch1 = (buf[3] << 8) | buf[2]; > + > + chip->als_cur_info.als_ch0 = ch0; > + chip->als_cur_info.als_ch1 = ch1; > + > + if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) would be easier to read if you set ret to lux max here an avoid jumping into the if statement below. > + goto return_max; > + > + if (ch0 == 0) { > + /* have no data, so return LAST VALUE */ > + ret = chip->als_cur_info.lux = 0; > + goto out_unlock; > + } > + /* calculate ratio */ > + ratio = (ch1 << 15) / ch0; > + /* convert to unscaled lux using the pointer to the table */ &taos_device_lux[0] perhaps? > + for (p = (struct taos_lux *) taos_device_lux; > + p->ratio != 0 && p->ratio < ratio; p++) > + ; > + > + if (p->ratio == 0) { > + lux = 0; > + } else { > + ch0lux = ((ch0 * p->ch0) + > + (gainadj[chip->taos_settings.als_gain].ch0 >> 1)) > + / gainadj[chip->taos_settings.als_gain].ch0; > + ch1lux = ((ch1 * p->ch1) + > + (gainadj[chip->taos_settings.als_gain].ch1 >> 1)) > + / gainadj[chip->taos_settings.als_gain].ch1; > + lux = ch0lux - ch1lux; > + } > + > + /* note: lux is 31 bit max at this point */ > + if (ch1lux > ch0lux) { > + dev_dbg(&client->dev, "No Data - Return last value\n"); > + ret = chip->als_cur_info.lux = 0; > + goto out_unlock; > + } > + > + /* adjust for active time scale */ > + if (chip->als_time_scale == 0) > + lux = 0; > + else > + lux = (lux + (chip->als_time_scale >> 1)) / > + chip->als_time_scale; > + > + /* adjust for active gain scale */ > + lux >>= 13; /* tables have factor of 8192 builtin for accuracy */ > + lux = (lux * chip->taos_settings.als_gain_trim + 500) / 1000; > + if (lux > LUX_CALC_OVER_FLOW) { /* check for overflow */ > +return_max: > + lux = LUX_CALC_OVER_FLOW; > + } > + > + /* Update the structure with the latest VALID lux. */ > + chip->als_cur_info.lux = lux; > + ret = lux; > + > +out_unlock: > + mutex_unlock(&chip->als_mutex); > + return ret; > +} > + > +/* > + * Obtain single reading and calculate the als_gain_trim (later used > + * to derive actual lux). > + * Return updated gain_trim value. > + */ > +int taos_als_calibrate(struct i2c_client *client) > +{ > + struct tsl2583_chip *chip = i2c_get_clientdata(client); > + u8 reg_val; > + unsigned int gain_trim_val; > + int ret; > + int lux_val; > + > + ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | TSL258X_CNTRL)); > + if (ret < 0) { > + dev_err(&client->dev, > + "taos_als_calibrate failed to reach the CNTRL register, ret=%d\n", > + ret); > + return ret; > + } > + > + reg_val = i2c_smbus_read_byte(client); > + if ((reg_val & (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWR_ON)) > + != (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWR_ON)) { > + dev_err(&client->dev, > + "taos_als_calibrate failed: device not powered on with ADC enabled\n"); > + return -ENODATA; > + } > + > + ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | TSL258X_CNTRL)); > + if (ret < 0) { > + dev_err(&client->dev, > + "taos_als_calibrate failed to reach the STATUS register, ret=%d\n", > + ret); > + return ret; > + } > + reg_val = i2c_smbus_read_byte(client); > + what if it's an error? Then we want to return that rather than -ENODATA. > + if ((reg_val & TSL258X_STA_ADC_VALID) != TSL258X_STA_ADC_VALID) { > + dev_err(&client->dev, > + "taos_als_calibrate failed: STATUS - ADC not valid.\n"); > + return -ENODATA; > + } > + lux_val = taos_get_lux(client); > + if (lux_val < 0) { > + dev_err(&client->dev, "taos_als_calibrate failed to get lux\n"); > + return lux_val; > + } > + gain_trim_val = (unsigned int) (((chip->taos_settings.als_cal_target) > + * chip->taos_settings.als_gain_trim) / lux_val); > + If it is worth printing this to the log, we don't care about where it is stored just what it is. Otherwise, shouldn't be here. > + dev_info(&client->dev, "taos_settings.als_cal_target = %d\n" > + "taos_settings.als_gain_trim = %d\nlux_val = %d\n", > + chip->taos_settings.als_cal_target, > + chip->taos_settings.als_gain_trim, > + lux_val); > + > + if ((gain_trim_val < 250) || (gain_trim_val > 4000)) { > + dev_err(&client->dev, > + "taos_als_calibrate failed: trim_val of %d is out of range\n", > + gain_trim_val); > + return -ENODATA; > + } > + chip->taos_settings.als_gain_trim = (int) gain_trim_val; > + > + return (int) gain_trim_val; > +} > + > +/* > + * Turn the device on. > + * Configuration must be set before calling this function. > + */ > +static int taos_chip_on(struct i2c_client *client) > +{ > + int i; > + int ret = 0; > + u8 *uP; > + u8 utmp; > + int als_count; > + int als_time; > + struct tsl2583_chip *chip = i2c_get_clientdata(client); > + > + /* and make sure we're not already on */ > + if (chip->taos_chip_status == TAOS_CHIP_WORKING) { > + /* if forcing a register update - turn off, then on */ > + dev_info(&client->dev, "device is already enabled\n"); -EINVAL perhaps? > + return -1; > + } > + > + /* determine als integration regster */ > + als_count = (chip->taos_settings.als_time * 100 + 135) / 270; > + if (als_count == 0) > + als_count = 1; /* ensure at least one cycle */ > + > + /* convert back to time (encompasses overrides) */ > + als_time = (als_count * 27 + 5) / 10; > + chip->taos_config[TSL258X_ALS_TIME] = 256 - als_count; > + > + /* Set the gain based on taos_settings struct */ > + chip->taos_config[TSL258X_GAIN] = chip->taos_settings.als_gain; > + > + /* set chip struct re scaling and saturation */ > + chip->als_saturation = als_count * 922; /* 90% of full scale */ > + chip->als_time_scale = (als_time + 25) / 50; > + We still don't know what SKATE is... Any publically available terms possible? > + /* SKATE Specific power-on / adc enable sequence > + * Power on the device 1st. */ > + utmp = TSL258X_CNTL_PWR_ON; > + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG | TSL258X_CNTRL, > + utmp); > + if (ret < 0) { > + dev_err(&client->dev, "taos_chip_on failed on CNTRL reg.\n"); > + return -1; > + } > + > + /* Use the following shadow copy for our delay before enabling ADC. > + * Write all the registers. */ > + for (i = 0, uP = chip->taos_config; i < TAOS_REG_MAX; i++) { > + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG + i, > + *uP++); > + if (ret < 0) { > + dev_err(&client->dev, > + "taos_chip_on failed on reg %d.\n", i); > + return -1; > + } > + } > + If not time critical lest make that a sleep. > + mdelay(3); > + /* NOW enable the ADC > + * initialize the desired mode of operation */ > + utmp = TSL258X_CNTL_PWR_ON | TSL258X_CNTL_ADC_ENBL; > + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG | TSL258X_CNTRL, > + utmp); > + if (ret < 0) { > + dev_err(&client->dev, "taos_chip_on failed on 2nd CTRL reg.\n"); > + return -1; > + } > + chip->taos_chip_status = TAOS_CHIP_WORKING; conventionally blank line here. > + return ret; > +} > + > +/* Turn the device OFF. */ > +static int taos_chip_off(struct i2c_client *client) > +{ > + struct tsl2583_chip *chip = i2c_get_clientdata(client); > + int ret; > + u8 utmp; > + > + /* turn device off */ Kind of obvious comment in this function ;) Please remove. > + chip->taos_chip_status = TAOS_CHIP_SLEEP; > + utmp = 0x00; Why not just put this value into the function call and get rid of utmp as a variable? > + ret = i2c_smbus_write_byte_data(client, TSL258X_CMD_REG | TSL258X_CNTRL, > + utmp); > + return ret; > +} > + > +/* Sysfs Interface Functions */ > +static ssize_t taos_device_id(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%s\n", chip->client->name); > +} > + > +static ssize_t taos_power_state_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%d\n", chip->taos_chip_status); > +} > + > +static ssize_t taos_power_state_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + unsigned long value; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + (wishful thought of the day) One day someone will write a nice standard 'boolean' test function that everyone will agree on... This works for me though ;) > + if (value == 0) > + taos_chip_off(chip->client); > + else > + taos_chip_on(chip->client); > + > + return len; > +} > + > +static ssize_t taos_gain_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%d\n", chip->taos_settings.als_gain); > +} > + > +static ssize_t taos_gain_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + unsigned long value; > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + I still wonder if there isn't a way of avoiding this index issue. It's horrible and really feels like something we ought to able to handle reasonably well... > + if (value > 3) { > + dev_err(dev, "Invalid Gain Index: Enter 0-3\n"); > + return -1; > + } else { > + chip->taos_settings.als_gain = value; > + } > + return len; > +} > + > +static ssize_t taos_gain_available_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + return sprintf(buf, "%s\n", "0 1 2 3"); > +} > + Just to confirm, is this a frequency in Hz? If it is can we renaming it to taos_als_frequency_show to avoid confusing me? > +static ssize_t taos_als_time_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%d\n", chip->taos_settings.als_time); > +} > + > +static ssize_t taos_als_time_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + unsigned long value; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + if ((value < 50) || (value > 650)) > + return -EINVAL; > + > + if (value % 50) > + return -EINVAL; > + > + chip->taos_settings.als_time = value; > + > + return len; > +} > + > +static ssize_t taos_als_time_available_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + return sprintf(buf, "%s\n", "50 100 150 200 250 300 350 400 450 500 550 600 650"); > +} > + > +static ssize_t taos_als_trim_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%d\n", chip->taos_settings.als_gain_trim); > +} > + > +static ssize_t taos_als_trim_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + unsigned long value; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + if (value) > + chip->taos_settings.als_gain_trim = value; > + > + return len; > +} > + > +static ssize_t taos_als_cal_target_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + > + return sprintf(buf, "%d\n", chip->taos_settings.als_cal_target); > +} > + > +static ssize_t taos_als_cal_target_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + unsigned long value; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + if (value) > + chip->taos_settings.als_cal_target = value; > + > + return len; > +} > + > +static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr, > + char *buf) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + int lux; > + > + lux = taos_get_lux(chip->client); > + > + return sprintf(buf, "%d\n", lux); > +} > + > +static ssize_t taos_do_calibrate(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + unsigned long value; > + > + if (strict_strtoul(buf, 0, &value)) > + return -EINVAL; > + > + if (value == 1) > + taos_als_calibrate(chip->client); > + > + return len; > +} > + > +static ssize_t taos_luxtable_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + int i; > + int offset = 0; > + > + for (i = 0; i < ARRAY_SIZE(taos_device_lux); i++) { > + offset += sprintf(buf + offset, "%d,%d,%d,", > + taos_device_lux[i].ratio, > + taos_device_lux[i].ch0, > + taos_device_lux[i].ch1); > + if (taos_device_lux[i].ratio == 0) { > + /* We just printed the first "0" entry. > + * Now get rid of the extra "," and break. */ > + offset--; > + break; > + } > + } > + > + offset += sprintf(buf + offset, "\n"); > + return offset; > +} > + > +static ssize_t taos_luxtable_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *indio_dev = dev_get_drvdata(dev); > + struct tsl2583_chip *chip = indio_dev->dev_data; > + int value[ARRAY_SIZE(taos_device_lux)]; > + int n; > + > + get_options(buf, ARRAY_SIZE(value), value); > + > + /* We now have an array of ints starting at value[1], and > + * enumerated by value[0]. > + * We expect each group of three ints is one table entry, > + * and the last table entry is all 0. > + */ > + n = value[0]; > + if ((n % 3) || n < 6 || n > (ARRAY_SIZE(taos_device_lux) - 3)) { > + dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n); > + return -EINVAL; > + } > + if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) { > + dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n); > + return -EINVAL; > + } > + > + if (chip->taos_chip_status == TAOS_CHIP_WORKING) > + taos_chip_off(chip->client); > + > + /* Zero out the table */ > + memset(taos_device_lux, 0, sizeof(taos_device_lux)); > + memcpy(taos_device_lux, &value[1], (value[0] * 4)); > + > + taos_chip_on(chip->client); > + > + return len; > +} > + > +static DEVICE_ATTR(name, S_IRUGO, taos_device_id, NULL); > +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, > + taos_power_state_show, taos_power_state_store); > + > +static DEVICE_ATTR(illuminance0_calibscale, S_IRUGO | S_IWUSR, > + taos_gain_show, taos_gain_store); > +static DEVICE_ATTR(illuminance0_calibscale_available, S_IRUGO, > + taos_gain_available_show, NULL); > + > +static DEVICE_ATTR(sampling_frequency, S_IRUGO | S_IWUSR, > + taos_als_time_show, taos_als_time_store); > +static DEVICE_ATTR(sampling_frequency_available, S_IRUGO, > + taos_als_time_available_show, NULL); > + scale as a stand alone attribute isn't defined. Please document this. Looking at what you do with it, it's another factor effecting the overal gain on the reading that reaches userspace. Ideally you'd roll this into your calibscale parameter, but I can see that would get complex to manage. Will have a think about this. In devices with a simple conversion function (adc's etc) we handle this by leaving this software value be applied by userspace (and output it as in_scale). The issue here that as far as userspace is concerned both of your scales have been applied before it sees the data and at different more or less random looking points in the calculation. Actually, looking at the calculation you could output illuminance0_raw and let userspace apply a multiplier based on your trim value and offset +0.5? If you want to hold trim in driver then just implement read and write to illuminance0_scale and have read only illuminance0_offset (rather tediously for this device, offset is applied before scale, so you'll need to divide 0.5 by whatever your trim is). We'll have to do pin down how to do this before moving out of staging so best to get it right now. > +static DEVICE_ATTR(scale, S_IRUGO | S_IWUSR, > + taos_als_trim_show, taos_als_trim_store); > + > +static DEVICE_ATTR(illuminance0_target, S_IRUGO | S_IWUSR, > + taos_als_cal_target_show, taos_als_cal_target_store); This needs documenting. Also if it is calculated units (e.g. lux) needs to be illuminance0_input_target to make that explicit. > + > +static DEVICE_ATTR(illuminance0_input, S_IRUGO, taos_lux_show, NULL); > +static DEVICE_ATTR(calibrate, S_IWUSR, NULL, taos_do_calibrate); calibrate needs documentation. > +static DEVICE_ATTR(lux_table, S_IRUGO | S_IWUSR, > + taos_luxtable_show, taos_luxtable_store); > + > +static struct attribute *sysfs_attrs_ctrl[] = { > + &dev_attr_name.attr, > + &dev_attr_power_state.attr, > + &dev_attr_illuminance0_calibscale.attr, > + &dev_attr_illuminance0_calibscale_available.attr, > + &dev_attr_sampling_frequency.attr, > + &dev_attr_sampling_frequency_available.attr, > + &dev_attr_scale.attr, > + &dev_attr_illuminance0_target.attr, > + &dev_attr_illuminance0_input.attr, > + &dev_attr_calibrate.attr, > + &dev_attr_lux_table.attr, > + NULL > +}; > + > +static struct attribute_group tsl2583_attribute_group = { > + .attrs = sysfs_attrs_ctrl, > +}; > + > +/* Use the default register values to identify the Taos device */ > +static int taos_skate_device(unsigned char *bufp) > +{ return ((bufp[TSL258X_CHIPID] & 0xf0) == 0x90); > + if (((bufp[TSL258X_CHIPID] & 0xf0) == 0x90)) > + /* tsl2583 */ > + return 1; > + /* else unknown */ > + return 0; > +} > + > +/* > + * Client probe function - When a valid device is found, the driver's device > + * data structure is updated, and initialization completes successfully. > + */ > +static int __devinit taos_probe(struct i2c_client *clientp, > + const struct i2c_device_id *idp) > +{ > + int i, ret = 0; > + unsigned char buf[MAX_DEVICE_REGS]; > + static struct tsl2583_chip *chip; > + > + if (!i2c_check_functionality(clientp->adapter, > + I2C_FUNC_SMBUS_BYTE_DATA)) { > + dev_err(&clientp->dev, > + "taos_probe() - i2c smbus byte data " > + "functions unsupported\n"); > + return -EOPNOTSUPP; > + } > + if (!i2c_check_functionality(clientp->adapter, > + I2C_FUNC_SMBUS_WORD_DATA)) { > + dev_warn(&clientp->dev, > + "taos_probe() - i2c smbus word data " > + "functions unsupported\n"); Why do you care? I'm not seeing them being used anyway. > + } > + if (!i2c_check_functionality(clientp->adapter, > + I2C_FUNC_SMBUS_BLOCK_DATA)) { > + dev_err(&clientp->dev, > + "taos_probe() - i2c smbus block data " > + "functions unsupported\n"); Nor these. > + } > + > + chip = kzalloc(sizeof(struct tsl2583_chip), GFP_KERNEL); > + if (!chip) { Malloc failure would be pretty unusual and knowing what it was probably won't be helpful, so no need to have this err printing here. > + dev_err(&clientp->dev, "taos_device_drvr: kmalloc for " > + "struct tsl2583_chip failed in taos_probe()\n"); > + return -ENOMEM; > + } > + > + chip->client = clientp; > + i2c_set_clientdata(clientp, chip); > + > + mutex_init(&chip->als_mutex); > + chip->taos_chip_status = TAOS_CHIP_UNKNOWN; /* uninitialized to start */ > + memcpy(chip->taos_config, taos_config, sizeof(chip->taos_config)); > + > + for (i = 0; i < MAX_DEVICE_REGS; i++) { > + ret = i2c_smbus_write_byte(clientp, > + (TSL258X_CMD_REG | (TSL258X_CNTRL + i))); > + if (ret < 0) { > + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd " > + "reg failed in taos_probe(), err = %d\n", ret); > + goto fail1; > + } > + buf[i] = i2c_smbus_read_byte(clientp); error handling for this read? > + } > + if (!taos_skate_device(buf)) { > + dev_info(&clientp->dev, "i2c device found but does not match " > + "expected id in taos_probe()\n"); > + goto fail1; > + } else { The sort of debug info you want to get rid of for production drivers. Doesn't tell anyone anything helpful. > + dev_info(&clientp->dev, "i2c device match in probe\n"); > + } > + ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | TSL258X_CNTRL)); > + if (ret < 0) { > + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg " > + "failed in taos_probe(), err = %d\n", ret); > + goto fail1; > + } > + chip->valid = 0; > + > + chip->iio_dev = iio_allocate_device(); > + if (!chip->iio_dev) { > + ret = -ENOMEM; > + dev_err(&clientp->dev, "iio allocation failed\n"); > + goto fail1; > + } > + > + chip->iio_dev->attrs = &tsl2583_attribute_group; > + chip->iio_dev->dev.parent = &clientp->dev; > + chip->iio_dev->dev_data = (void *)(chip); > + chip->iio_dev->driver_module = THIS_MODULE; > + chip->iio_dev->modes = INDIO_DIRECT_MODE; > + ret = iio_device_register(chip->iio_dev); > + if (ret) { > + dev_err(&clientp->dev, "iio registration failed\n"); > + goto fail1; > + } > + > + /* Load up the V2 defaults (these are hard coded defaults for now) */ > + taos_defaults(chip); > + > + /* Make sure the chip is on */ > + taos_chip_on(clientp); > + > + dev_info(&clientp->dev, "Light sensor found.\n"); > + return 0; > + > +fail1: > + kfree(chip); > + > + return ret; > +} > + > +static int __devexit taos_remove(struct i2c_client *client) > +{ > + struct tsl2583_chip *chip = i2c_get_clientdata(client); > + > + iio_device_unregister(chip->iio_dev); > + > + kfree(chip); > + return 0; > +} > + > +static struct i2c_device_id taos_idtable[] = { > + { "tsl2580", 0 }, > + { "tsl2581", 1 }, > + { "tsl2583", 2 }, > + {} > +}; > +MODULE_DEVICE_TABLE(i2c, taos_idtable); > + > +/* Driver definition */ > +static struct i2c_driver taos_driver = { > + .driver = { > + .name = "tsl2583", > + }, > + .id_table = taos_idtable, > + .probe = taos_probe, > + .remove = __devexit_p(taos_remove), > +}; > + > +static int __init taos_init(void) > +{ > + return i2c_add_driver(&taos_driver); > +} > + > +static void __exit taos_exit(void) > +{ > + i2c_del_driver(&taos_driver); > +} > + > +module_init(taos_init); > +module_exit(taos_exit); > + > +MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>"); > +MODULE_DESCRIPTION("TAOS tsl2583 ambient light sensor driver"); > +MODULE_LICENSE("GPL"); > + > -- > 1.7.0.4 > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-iio" 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] 10+ messages in thread
* RE: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver 2011-03-21 19:07 ` Jonathan Cameron @ 2011-03-23 1:07 ` Jon Brenner 2011-03-23 11:06 ` Jonathan Cameron 0 siblings, 1 reply; 10+ messages in thread From: Jon Brenner @ 2011-03-23 1:07 UTC (permalink / raw) To: Jonathan Cameron; +Cc: linux-iio, Linux Kernel Sm9uYXRoYW4sIGV0IGFsLA0KDQpBZ2FpbiwgdGhhbmsgeW91IGZvciB0YWtpbmcgdGhlIHRpbWUg dG8gcmV2aWV3IHRoZSBsYXRlc3Qgc3VibWlzc2lvbi4NCkkgaGF2ZSBpbXBsZW1lbnRlZCBhbGwg cmVjb21tZW5kYXRpb25zIG1hZGUgKHdpdGggdGhlIGV4Y2VwdGlvbnMgbm90ZWQgYmVsb3cpLg0K DQpJIGhhdmUgYWxzbyBhZGRlZCB0d28gbmV3IGZ1bmN0aW9ucyAobm90IHNlZW4gaGVyZSk6DQon dGFvc19zdXNwZW5kJywgYW5kICd0YW9zX3Jlc3VtZScNCg0KVGhlc2UgY2hhbmdlcyBhbmQgY29t bWVudHMgd2lsbCBiZSBzdWJtaXR0ZWQgaW4gdGhlIG5leHQgcGF0Y2ggW1BBVENIIFYzXSBzdWJt aXNzaW9uIHdoaWNoIEkgd2lsbCBzdWJtaXQgc2hvcnRseSAoYWZ0ZXIgdGVzdGluZy92ZXJpZmlj YXRpb24pLiANCg0KUmVzcGVjdGZ1bGx5LA0KSm9uIA0KDQotLS0tLU9yaWdpbmFsIE1lc3NhZ2Ut LS0tLQ0KQXMgSSBwbSdkIHlvdSB0aGUgb3RoZXIgZGF5LCBwbGVhc2UgcmVtZW1iZXIgdG8gbWFr ZSB2ZXJzaW9uIG9mIHBhdGNoIGNsZWFyIGluIHRpdGxlLCBhbmQgaW5jbHVkZSBkZXRhaWxzIG9m IHdoYXQgaGFzIGNoYW5nZWQgc2luY2UgcHJldmlvdXMgdmVyc2lvbi4NCk9LIC0gTkVYVCBQQVRD SCBXSUxMIElORElDQVRFIFZFUlNJT04gMw0KDQpXSUxMIFJFTU9WRSBTRU5TT1JTXyBQUkVGSVgg RlJPTSBLQ09ORklHICYgTUFLRUZJTEUNCg0KQURERUQvTU9WRUQvQ1JFQVRFRCBET0NVTUVOVEFU SU9OIEFTIFJFQ09NTUVOREVEDQoNCi0tLS0tIHNuaXAgLS0tLS0tLS0tLS0tDQo+ICsvKg0KPiAr ICogUHJvdmlkZXMgaW5pdGlhbCBvcGVyYXRpb25hbCBwYXJhbWV0ZXIgZGVmYXVsdHMuDQo+ICsg KiBUaGVzZSBkZWZhdWx0cyBtYXkgYmUgY2hhbmdlZCB0aHJvdWdoIHRoZSBkZXZpY2UncyBzeXNm cyBmaWxlcy4NCj4gKyAqLw0KSG93IGFib3V0IHBhc2luZyBpbiB0YW9zX3NldHRpbmdzIGFuZCBt YWtpbmcgYWxsIG9mIHRoaXMgZnVuYyBhIGJpdCBtb3JlIHJlYWRhYmxlPw0KUFJFRkVSIFRPIFVT RSBERUZBVUxUUyBNRVRIT0QNCg0KPiArc3RhdGljIHZvaWQgdGFvc19kZWZhdWx0cyhzdHJ1Y3Qg dHNsMjU4M19jaGlwICpjaGlwKSB7DQo+ICsJLyogT3BlcmF0aW9uYWwgcGFyYW1ldGVycyAqLw0K PiArCWNoaXAtPnRhb3Nfc2V0dGluZ3MuYWxzX3RpbWUgPSA0NTA7DQo+ICsJLyogbXVzdCBiZSBh IG11bHRpcGxlIG9mIDUwbVMgKi8NCj4gKwljaGlwLT50YW9zX3NldHRpbmdzLmFsc19nYWluID0g MjsNCj4gKwkvKiB0aGlzIGlzIGFjdHVhbGx5IGFuIGluZGV4IGludG8gdGhlIGdhaW4gdGFibGUg Ki8NCj4gKwkvKiBhc3N1bWUgY2xlYXIgZ2xhc3MgYXMgZGVmYXVsdCAqLw0KPiArCWNoaXAtPnRh b3Nfc2V0dGluZ3MuYWxzX2dhaW5fdHJpbSA9IDEwMDA7DQo+ICsJLyogZGVmYXVsdCBnYWluIHRy aW0gdG8gYWNjb3VudCBmb3IgYXBlcnR1cmUgZWZmZWN0cyAqLw0KPiArCWNoaXAtPnRhb3Nfc2V0 dGluZ3MuYWxzX2NhbF90YXJnZXQgPSAxMzA7DQo+ICsJLyogS25vd24gZXh0ZXJuYWwgQUxTIHJl YWRpbmcgdXNlZCBmb3IgY2FsaWJyYXRpb24gKi8gfQ0KPiArDQoNCi0tLS0tIHNuaXAgLS0tLS0t LS0tLS0tDQo+ICsJaWYgKChjaDAgPj0gY2hpcC0+YWxzX3NhdHVyYXRpb24pIHx8IChjaDEgPj0g Y2hpcC0+YWxzX3NhdHVyYXRpb24pKQ0Kd291bGQgYmUgZWFzaWVyIHRvIHJlYWQgaWYgeW91IHNl dCByZXQgdG8gbHV4IG1heCBoZXJlIGFuIGF2b2lkIGp1bXBpbmcgaW50bw0KdGhlIGlmIHN0YXRl bWVudCBiZWxvdy4NCk5PIC0gVFNMMjU4WF9MVVhfQ0FMQ19PVkVSX0ZMT1cgTkVFRFMgVE8gUEFT U0VEIFVQLiAgDQoJTVVURVggTkVFRFMgVE8gQkUgVU5MT0NLRUQuIA0KCVRIRU4gUkVUVVJOLg0K PiArCQlnb3RvIHJldHVybl9tYXg7DQoNCi0tLS0tIHNuaXAgLS0tLS0tLS0tLS0tDQomdGFvc19k ZXZpY2VfbHV4WzBdIHBlcmhhcHM/DQpOTyAtIENBU1QgTUFLRVMgSVQgTU9SRSBPQlZJT1VTIC0g YXQgbGVhc3QgdG8gbWUgOy0pDQo+ICsJZm9yIChwID0gKHN0cnVjdCB0YW9zX2x1eCAqKSB0YW9z X2RldmljZV9sdXg7DQoNCi0tLS0tIHNuaXAgLS0tLS0tLS0tLS0tDQo+ICsNCklmIG5vdCB0aW1l IGNyaXRpY2FsIGxlc3QgbWFrZSB0aGF0IGEgc2xlZXAuDQpOTyAtIFRJTUUgSVMgUkVRVUlSRUQg Rk9SIERFVklDRSBUTyBTRVRUTEUgQkVUV0VFTiBQT1dFUk9OIEFORCBBREMgRU5BQkxFIC0gRE9O J1QgV0FOVCBUTyBNQUtFIElUIEFOWSBMT05HRVIgVEhBTiBORUNFU1NBUlkuDQo+ICsJbWRlbGF5 KDMpOw0KPiArCS8qIE5PVyBlbmFibGUgdGhlIEFEQw0KDQoNCi0tLS0tIHNuaXAgLS0tLS0tLS0t LS0tDQpJIHN0aWxsIHdvbmRlciBpZiB0aGVyZSBpc24ndCBhIHdheSBvZiBhdm9pZGluZyB0aGlz IGluZGV4IGlzc3VlLg0KSXQncyBob3JyaWJsZSBhbmQgcmVhbGx5IGZlZWxzIGxpa2Ugc29tZXRo aW5nIHdlIG91Z2h0IHRvIGFibGUNCnRvIGhhbmRsZSByZWFzb25hYmx5IHdlbGwuLi4NCkJFQ0FV U0UgVEhFIENIMCBBTkQgQ0gxIERJVkVSR0UgQVQgSElHSCBHQUlOUyAtLSBJTkRFWCBJUyBCRVRU RVIgVEhBTiBVU0lORyBDSE8gT1IgQ0gxIFZBTFVFIA0KKCBBUyBFSVRIRVIgT05FIE9WRVIgVEhF IE9USEVSIFdPVUxEIEJFIFdST05HIDoteyApDQo+ICsJaWYgKHZhbHVlID4gMykgew0KPiArCQlk ZXZfZXJyKGRldiwgIkludmFsaWQgR2FpbiBJbmRleDogRW50ZXIgMC0zXG4iKTsNCj4gKwkJcmV0 dXJuIC0xOw0KPiArCX0gZWxzZSB7DQo+ICsJCWNoaXAtPnRhb3Nfc2V0dGluZ3MuYWxzX2dhaW4g PSB2YWx1ZTsNCj4gKwl9DQo+ICsJcmV0dXJuIGxlbjsNCj4gK30NCg0KLS0tLS0gc25pcCAtLS0t LS0tLS0tLS0NCkp1c3QgdG8gY29uZmlybSwgaXMgdGhpcyBhIGZyZXF1ZW5jeSBpbiBIej8gSWYg aXQgaXMNCmNhbiB3ZSByZW5hbWluZyBpdCB0byB0YW9zX2Fsc19mcmVxdWVuY3lfc2hvdyB0bw0K YXZvaWQgY29uZnVzaW5nIG1lPw0KDQpUSElTIElTIFRIRSBJTlRFUk5BTCBBTFMgSU5URUdSQVRJ T04gVElNRSBGT1IgVEhFIEFEQyBDSEFOTkVMUw0KSSBTSE9FIEhPUk5FRCBJVCBJTlRPIFNBTVBM SU5HIEZSRVFVRU5DWSBUTyBIRUxQIEFMRVZJQVRFIFRIRSBBQkkgQU5HU1QNCg0KPiArc3RhdGlj IHNzaXplX3QgdGFvc19hbHNfdGltZV9zaG93KHN0cnVjdCBkZXZpY2UgKmRldiwNCj4gKyAgICBz dHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQ0KPiArew0KPiArCXN0cnVj dCBpaW9fZGV2ICppbmRpb19kZXYgPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsNCj4gKwlzdHJ1Y3Qg dHNsMjU4M19jaGlwICpjaGlwID0gaW5kaW9fZGV2LT5kZXZfZGF0YTsNCj4gKw0KPiArCXJldHVy biBzcHJpbnRmKGJ1ZiwgIiVkXG4iLCBjaGlwLT50YW9zX3NldHRpbmdzLmFsc190aW1lKTsNCj4g K30NCg0KLS0tLS0gc25pcCAtLS0tLS0tLS0tLS0NCnNjYWxlIGFzIGEgc3RhbmQgYWxvbmUgYXR0 cmlidXRlIGlzbid0IGRlZmluZWQuIFBsZWFzZSBkb2N1bWVudCB0aGlzLg0KTG9va2luZyBhdCB3 aGF0IHlvdSBkbyB3aXRoIGl0LCBpdCdzIGFub3RoZXIgZmFjdG9yIGVmZmVjdGluZyB0aGUgb3Zl cmFsDQpnYWluIG9uIHRoZSByZWFkaW5nIHRoYXQgcmVhY2hlcyB1c2Vyc3BhY2UuICBJZGVhbGx5 IHlvdSdkIHJvbGwgdGhpcw0KaW50byB5b3VyIGNhbGlic2NhbGUgcGFyYW1ldGVyLCBidXQgSSBj YW4gc2VlIHRoYXQgd291bGQgZ2V0IGNvbXBsZXgNCnRvIG1hbmFnZS4gV2lsbCBoYXZlIGEgdGhp bmsgYWJvdXQgdGhpcy4gSW4gZGV2aWNlcyB3aXRoIGEgc2ltcGxlIGNvbnZlcnNpb24NCmZ1bmN0 aW9uIChhZGMncyBldGMpIHdlIGhhbmRsZSB0aGlzIGJ5IGxlYXZpbmcgdGhpcyBzb2Z0d2FyZSB2 YWx1ZQ0KYmUgYXBwbGllZCBieSB1c2Vyc3BhY2UgKGFuZCBvdXRwdXQgaXQgYXMgaW5fc2NhbGUp LiBUaGUgaXNzdWUgaGVyZSB0aGF0DQphcyBmYXIgYXMgdXNlcnNwYWNlIGlzIGNvbmNlcm5lZCBi b3RoIG9mIHlvdXIgc2NhbGVzIGhhdmUgYmVlbiBhcHBsaWVkIGJlZm9yZQ0KaXQgc2VlcyB0aGUg ZGF0YSBhbmQgYXQgZGlmZmVyZW50IG1vcmUgb3IgbGVzcyByYW5kb20gbG9va2luZyBwb2ludHMg aW4NCnRoZSBjYWxjdWxhdGlvbi4NCg0KQWN0dWFsbHksIGxvb2tpbmcgYXQgdGhlIGNhbGN1bGF0 aW9uIHlvdSBjb3VsZCBvdXRwdXQgaWxsdW1pbmFuY2UwX3Jhdw0KYW5kIGxldCB1c2Vyc3BhY2Ug YXBwbHkgYSBtdWx0aXBsaWVyIGJhc2VkIG9uIHlvdXIgdHJpbSB2YWx1ZSBhbmQgb2Zmc2V0DQor MC41PyAgSWYgeW91IHdhbnQgdG8gaG9sZCB0cmltIGluIGRyaXZlciB0aGVuIGp1c3QgaW1wbGVt ZW50DQpyZWFkIGFuZCB3cml0ZSB0bw0KDQppbGx1bWluYW5jZTBfc2NhbGUNCmFuZCBoYXZlIHJl YWQgb25seQ0KaWxsdW1pbmFuY2UwX29mZnNldCAocmF0aGVyIHRlZGlvdXNseSBmb3IgdGhpcyBk ZXZpY2UsIG9mZnNldCBpcyBhcHBsaWVkDQpiZWZvcmUgc2NhbGUsIHNvIHlvdSdsbCBuZWVkIHRv IGRpdmlkZSAwLjUgYnkgd2hhdGV2ZXIgeW91ciB0cmltIGlzKS4NCg0KV2UnbGwgaGF2ZSB0byBk byBwaW4gZG93biBob3cgdG8gZG8gdGhpcyBiZWZvcmUgbW92aW5nIG91dCBvZiBzdGFnaW5nDQpz byBiZXN0IHRvIGdldCBpdCByaWdodCBub3cuDQoNCkNIQU5HRUQgVE8gSUxMVU1JTkFOQ0UwX1ND QUxFDQoNCkxJRkUgV09VTEUgQkUgTklDRSBJRiBXRSBDT1VMRCBKVVNUIFBBU1MgVEhFIFJBVyBE QVRBIFVQIFRPIFVTRVJTUEFDRQ0KQlVUIFdFIEhBVkUgQ1VTVE9NRVJTIFdITyBSRVFVSVJFIElU IFRPIENPTUUgVVAgQ0FMQ1VMQVRFRCBXSVRIDQpUSEUgTVVMVElQTElFUiBGQUNUT1JFRCBJTg0K DQotLS0tLSBzbmlwIC0tLS0tLS0tLS0tLQ0KPiArCWZvciAoaSA9IDA7IGkgPCBNQVhfREVWSUNF X1JFR1M7IGkrKykgew0KPiArCQlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZShjbGllbnRwLA0K PiArCQkJCShUU0wyNThYX0NNRF9SRUcgfCAoVFNMMjU4WF9DTlRSTCArIGkpKSk7DQo+ICsJCWlm IChyZXQgPCAwKSB7DQo+ICsJCQlkZXZfZXJyKCZjbGllbnRwLT5kZXYsICJpMmNfc21idXNfd3Jp dGVfYnl0ZSgpIHRvIGNtZCAiDQo+ICsJCQkJInJlZyBmYWlsZWQgaW4gdGFvc19wcm9iZSgpLCBl cnIgPSAlZFxuIiwgcmV0KTsNCj4gKwkJCWdvdG8gZmFpbDE7DQo+ICsJCX0NCj4gKwkJYnVmW2ld ID0gaTJjX3NtYnVzX3JlYWRfYnl0ZShjbGllbnRwKTsNCiAgZXJyb3IgaGFuZGxpbmcgZm9yIHRo aXMgcmVhZD8NClZBTFVFIElTIFVOSU1QT1JUQU5UIC0gQlVUIE1BS0lORyBTVVJFIFdFIENBTiBK VVNUIFJFQUQgQUxMIDMyIFJFR0lTVEVSIExPQ0FUSU9OUyBJUy4uDQoNCi0tLS0tIHNuaXAgLS0t LS0tLS0tLS0tDQoNCj4gKwl9DQo+ICsJaWYgKCF0YW9zX3NrYXRlX2RldmljZShidWYpKSB7DQo+ ICsJCWRldl9pbmZvKCZjbGllbnRwLT5kZXYsICJpMmMgZGV2aWNlIGZvdW5kIGJ1dCBkb2VzIG5v dCBtYXRjaCAiDQo+ICsJCQkiZXhwZWN0ZWQgaWQgaW4gdGFvc19wcm9iZSgpXG4iKTsNCj4gKwkJ Z290byBmYWlsMTsNCj4gKwl9IGVsc2Ugew0KVGhlIHNvcnQgb2YgZGVidWcgaW5mbyB5b3Ugd2Fu dCB0byBnZXQgcmlkIG9mIGZvciBwcm9kdWN0aW9uIGRyaXZlcnMuICBEb2Vzbid0DQp0ZWxsIGFu eW9uZSBhbnl0aGluZyBoZWxwZnVsLg0KTk8gLSBETyBOT1QgQUdSRUUgLSBJRiBBIENVU1RPTUVS IEVYUEVDVFMgT05FIERFVklDRSBCVVQgSEFTIFNPTUVIT1cgSU5TVEFMTEVEIEEgRElGRkVSRU5U IE9ORQ0KQVQgUFJPRFVDVElPTiBUSU1FLCBUSElTIFdJTEwgSEVMUCBJREVOVElGWSBUSEUgSVNT VUUuICANCihJRS4gV0FOVEVEIEEgVEFPUyBBTFMgREVWSUNFIEJVVCBJTlNUQUxMRUQgQSBUQU9T IFBST1gvQUxTIERFVklDRSkNCkZJUlNUIFBBUlQgSU5ESUNBVEVTIFRIQVQuICBTRUNPTkQgUEFS VCBJUyBDT05GSVJNQVRJT04gVEhBVCBERVZJQ0UgV0FTIElERU5USUZJRUQgVE8gU1lTVEVNLg0K DQoNCg0K ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver 2011-03-23 1:07 ` Jon Brenner @ 2011-03-23 11:06 ` Jonathan Cameron 2011-03-23 22:38 ` Jon Brenner 0 siblings, 1 reply; 10+ messages in thread From: Jonathan Cameron @ 2011-03-23 11:06 UTC (permalink / raw) To: Jon Brenner; +Cc: linux-iio, Linux Kernel On 03/23/11 01:07, Jon Brenner wrote: > Jonathan, et al, > > Again, thank you for taking the time to review the latest submission. > I have implemented all recommendations made (with the exceptions noted below). > > I have also added two new functions (not seen here): > 'taos_suspend', and 'taos_resume' > > These changes and comments will be submitted in the next patch [PATCH V3] submission which I will submit shortly (after testing/verification). > > Respectfully, > Jon > > -----Original Message----- > As I pm'd you the other day, please remember to make version of patch clear in title, and include details of what has changed since previous version. > OK - NEXT PATCH WILL INDICATE VERSION 3 > > WILL REMOVE SENSORS_ PREFIX FROM KCONFIG & MAKEFILE > > ADDED/MOVED/CREATED DOCUMENTATION AS RECOMMENDED > > ----- snip ------------ >> +/* >> + * Provides initial operational parameter defaults. >> + * These defaults may be changed through the device's sysfs files. >> + */ > How about pasing in taos_settings and making all of this func a bit more readable? > PREFER TO USE DEFAULTS METHOD Ah, I didn't make clear what I meant here. It was simply an observation that having static void taos_defaults(struct taos_settings *settings) { settings->als_time = 450; etc. } would be easier to read. > >> +static void taos_defaults(struct tsl2583_chip *chip) { >> + /* Operational parameters */ >> + chip->taos_settings.als_time = 450; >> + /* must be a multiple of 50mS */ >> + chip->taos_settings.als_gain = 2; >> + /* this is actually an index into the gain table */ >> + /* assume clear glass as default */ >> + chip->taos_settings.als_gain_trim = 1000; >> + /* default gain trim to account for aperture effects */ >> + chip->taos_settings.als_cal_target = 130; >> + /* Known external ALS reading used for calibration */ } >> + > > ----- snip ------------ >> + if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) > would be easier to read if you set ret to lux max here an avoid jumping into > the if statement below. > NO - TSL258X_LUX_CALC_OVER_FLOW NEEDS TO PASSED UP. > MUTEX NEEDS TO BE UNLOCKED. > THEN RETURN. Sorry, should have said jump to out_unlock having set ret = LUX_CALC_OVER_FLOW; Just makes for marginally cleaner program flow to my mind (though I don't really care about this one). >> + goto return_max; > > ----- snip ------------ > &taos_device_lux[0] perhaps? > NO - CAST MAKES IT MORE OBVIOUS - at least to me ;-) >> + for (p = (struct taos_lux *) taos_device_lux; > > ----- snip ------------ >> + > If not time critical lest make that a sleep. > NO - TIME IS REQUIRED FOR DEVICE TO SETTLE BETWEEN POWERON AND ADC ENABLE - DON'T WANT TO MAKE IT ANY LONGER THAN NECESSARY. But do you want to spin the processor during this time instead of getting on with something useful? I guess it depends on how critical speed is in the taos_chip_on function. I'd say this device is slow enough that a possible extra delay doesn't really matter. >> + mdelay(3); >> + /* NOW enable the ADC > > > ----- snip ------------ > I still wonder if there isn't a way of avoiding this index issue. > It's horrible and really feels like something we ought to able > to handle reasonably well... > BECAUSE THE CH0 AND CH1 DIVERGE AT HIGH GAINS -- INDEX IS BETTER THAN USING CHO OR CH1 VALUE > ( AS EITHER ONE OVER THE OTHER WOULD BE WRONG :-{ ) I can see your point to a certain extent. The counter argument is that doing it with an index precludes ever touching this with any remotely general purpose user space code. Given it's an internal gain anyway is the precise value that critical? Basically is user space ever going to care about the difference between those those values? Another option would be to have a gain for each channel as separate attributes (clearly writing to one would change the other). >> + if (value > 3) { >> + dev_err(dev, "Invalid Gain Index: Enter 0-3\n"); >> + return -1; >> + } else { >> + chip->taos_settings.als_gain = value; >> + } >> + return len; >> +} > > ----- snip ------------ > Just to confirm, is this a frequency in Hz? If it is > can we renaming it to taos_als_frequency_show to > avoid confusing me? > > THIS IS THE INTERNAL ALS INTEGRATION TIME FOR THE ADC CHANNELS > I SHOE HORNED IT INTO SAMPLING FREQUENCY TO HELP ALEVIATE THE ABI ANGST That's good but it does have to match the units specified in the ABI as well. > >> +static ssize_t taos_als_time_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *indio_dev = dev_get_drvdata(dev); >> + struct tsl2583_chip *chip = indio_dev->dev_data; >> + >> + return sprintf(buf, "%d\n", chip->taos_settings.als_time); >> +} > > ----- snip ------------ > scale as a stand alone attribute isn't defined. Please document this. > Looking at what you do with it, it's another factor effecting the overal > gain on the reading that reaches userspace. Ideally you'd roll this > into your calibscale parameter, but I can see that would get complex > to manage. Will have a think about this. In devices with a simple conversion > function (adc's etc) we handle this by leaving this software value > be applied by userspace (and output it as in_scale). The issue here that > as far as userspace is concerned both of your scales have been applied before > it sees the data and at different more or less random looking points in > the calculation. > > Actually, looking at the calculation you could output illuminance0_raw > and let userspace apply a multiplier based on your trim value and offset > +0.5? If you want to hold trim in driver then just implement > read and write to > > illuminance0_scale > and have read only > illuminance0_offset (rather tediously for this device, offset is applied > before scale, so you'll need to divide 0.5 by whatever your trim is). > > We'll have to do pin down how to do this before moving out of staging > so best to get it right now. > > CHANGED TO ILLUMINANCE0_SCALE > > LIFE WOULE BE NICE IF WE COULD JUST PASS THE RAW DATA UP TO USERSPACE > BUT WE HAVE CUSTOMERS WHO REQUIRE IT TO COME UP CALCULATED WITH > THE MULTIPLIER FACTORED IN Sure. It's a fiddly calculation so I can kind of see their point. These light sensors are all a pain :) > > ----- snip ------------ >> + for (i = 0; i < MAX_DEVICE_REGS; i++) { >> + ret = i2c_smbus_write_byte(clientp, >> + (TSL258X_CMD_REG | (TSL258X_CNTRL + i))); >> + if (ret < 0) { >> + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd " >> + "reg failed in taos_probe(), err = %d\n", ret); >> + goto fail1; >> + } >> + buf[i] = i2c_smbus_read_byte(clientp); > error handling for this read? > VALUE IS UNIMPORTANT - BUT MAKING SURE WE CAN JUST READ ALL 32 REGISTER LOCATIONS IS.. > > ----- snip ------------ > >> + } >> + if (!taos_skate_device(buf)) { >> + dev_info(&clientp->dev, "i2c device found but does not match " >> + "expected id in taos_probe()\n"); >> + goto fail1; >> + } else { > The sort of debug info you want to get rid of for production drivers. Doesn't > tell anyone anything helpful. > NO - DO NOT AGREE - IF A CUSTOMER EXPECTS ONE DEVICE BUT HAS SOMEHOW INSTALLED A DIFFERENT ONE > AT PRODUCTION TIME, THIS WILL HELP IDENTIFY THE ISSUE. > (IE. WANTED A TAOS ALS DEVICE BUT INSTALLED A TAOS PROX/ALS DEVICE) > FIRST PART INDICATES THAT. SECOND PART IS CONFIRMATION THAT DEVICE WAS IDENTIFIED TO SYSTEM. I'm happy with the error one. Just don't see the point in saying 'everything is as expected'. The mere absence of the error indicates that just fine! Jonathan ^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver 2011-03-23 11:06 ` Jonathan Cameron @ 2011-03-23 22:38 ` Jon Brenner 2011-03-24 11:15 ` Jonathan Cameron 0 siblings, 1 reply; 10+ messages in thread From: Jon Brenner @ 2011-03-23 22:38 UTC (permalink / raw) To: Jonathan Cameron; +Cc: linux-iio, linux-kernel SGkgSm9uYXRoYW4sDQpCZWxvdyBhcmUgYSBmZXcgY29tbWVudHMvcXVlc3Rpb25zIHRvIHlvdXIg bGF0ZXN0IHJlc3BvbnNlLg0KQW55IGRpcmVjdGlvbiBpcyBncmVhdGx5IGFwcHJlY2lhdGVkLg0K DQpKb24NCg0KDQotLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KRnJvbTogSm9uYXRoYW4gQ2Ft ZXJvbiBbbWFpbHRvOmppYzIzQGNhbS5hYy51a10gDQpTZW50OiBXZWRuZXNkYXksIE1hcmNoIDIz LCAyMDExIDY6MDcgQU0NClRvOiBKb24gQnJlbm5lcg0KQ2M6IGxpbnV4LWlpbzsgTGludXggS2Vy bmVsDQpTdWJqZWN0OiBSZTogW1BBVENIIDIuNi4zOC1yYzddVEFPUyAyNTh4OiBEZXZpY2UgRHJp dmVyDQoNCk9uIDAzLzIzLzExIDAxOjA3LCBKb24gQnJlbm5lciB3cm90ZToNCj4gSm9uYXRoYW4s IGV0IGFsLA0KPiANCj4gQWdhaW4sIHRoYW5rIHlvdSBmb3IgdGFraW5nIHRoZSB0aW1lIHRvIHJl dmlldyB0aGUgbGF0ZXN0IHN1Ym1pc3Npb24uDQo+IEkgaGF2ZSBpbXBsZW1lbnRlZCBhbGwgcmVj b21tZW5kYXRpb25zIG1hZGUgKHdpdGggdGhlIGV4Y2VwdGlvbnMgbm90ZWQgYmVsb3cpLg0KPiAN Cj4gSSBoYXZlIGFsc28gYWRkZWQgdHdvIG5ldyBmdW5jdGlvbnMgKG5vdCBzZWVuIGhlcmUpOg0K PiAndGFvc19zdXNwZW5kJywgYW5kICd0YW9zX3Jlc3VtZScNCj4gDQo+IFRoZXNlIGNoYW5nZXMg YW5kIGNvbW1lbnRzIHdpbGwgYmUgc3VibWl0dGVkIGluIHRoZSBuZXh0IHBhdGNoIFtQQVRDSCBW M10gc3VibWlzc2lvbiB3aGljaCBJIHdpbGwgc3VibWl0IHNob3J0bHkgKGFmdGVyIHRlc3Rpbmcv dmVyaWZpY2F0aW9uKS4gDQo+IA0KPiBSZXNwZWN0ZnVsbHksDQo+IEpvbg0KPiANCj4gLS0tLS1P cmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gQXMgSSBwbSdkIHlvdSB0aGUgb3RoZXIgZGF5LCBwbGVh c2UgcmVtZW1iZXIgdG8gbWFrZSB2ZXJzaW9uIG9mIHBhdGNoIGNsZWFyIGluIHRpdGxlLCBhbmQg aW5jbHVkZSBkZXRhaWxzIG9mIHdoYXQgaGFzIGNoYW5nZWQgc2luY2UgcHJldmlvdXMgdmVyc2lv bi4NCj4gT0sgLSBORVhUIFBBVENIIFdJTEwgSU5ESUNBVEUgVkVSU0lPTiAzDQo+IA0KPiBXSUxM IFJFTU9WRSBTRU5TT1JTXyBQUkVGSVggRlJPTSBLQ09ORklHICYgTUFLRUZJTEUNCj4gDQo+IEFE REVEL01PVkVEL0NSRUFURUQgRE9DVU1FTlRBVElPTiBBUyBSRUNPTU1FTkRFRA0KPiANCj4gLS0t LS0gc25pcCAtLS0tLS0tLS0tLS0NCj4+ICsvKg0KPj4gKyAqIFByb3ZpZGVzIGluaXRpYWwgb3Bl cmF0aW9uYWwgcGFyYW1ldGVyIGRlZmF1bHRzLg0KPj4gKyAqIFRoZXNlIGRlZmF1bHRzIG1heSBi ZSBjaGFuZ2VkIHRocm91Z2ggdGhlIGRldmljZSdzIHN5c2ZzIGZpbGVzLg0KPj4gKyAqLw0KPiBI b3cgYWJvdXQgcGFzaW5nIGluIHRhb3Nfc2V0dGluZ3MgYW5kIG1ha2luZyBhbGwgb2YgdGhpcyBm dW5jIGEgYml0IG1vcmUgcmVhZGFibGU/DQo+IFBSRUZFUiBUTyBVU0UgREVGQVVMVFMgTUVUSE9E DQpBaCwgSSBkaWRuJ3QgbWFrZSBjbGVhciB3aGF0IEkgbWVhbnQgaGVyZS4gSXQgd2FzIHNpbXBs eSBhbiBvYnNlcnZhdGlvbiB0aGF0IGhhdmluZw0KDQpzdGF0aWMgdm9pZCB0YW9zX2RlZmF1bHRz KHN0cnVjdCB0YW9zX3NldHRpbmdzICpzZXR0aW5ncykgew0KCXNldHRpbmdzLT5hbHNfdGltZSA9 IDQ1MDsNCmV0Yy4NCn0gDQoNCndvdWxkIGJlIGVhc2llciB0byByZWFkLg0KPiANCj4+ICtzdGF0 aWMgdm9pZCB0YW9zX2RlZmF1bHRzKHN0cnVjdCB0c2wyNTgzX2NoaXAgKmNoaXApIHsNCj4+ICsJ LyogT3BlcmF0aW9uYWwgcGFyYW1ldGVycyAqLw0KPj4gKwljaGlwLT50YW9zX3NldHRpbmdzLmFs c190aW1lID0gNDUwOw0KPj4gKwkvKiBtdXN0IGJlIGEgbXVsdGlwbGUgb2YgNTBtUyAqLw0KPj4g KwljaGlwLT50YW9zX3NldHRpbmdzLmFsc19nYWluID0gMjsNCj4+ICsJLyogdGhpcyBpcyBhY3R1 YWxseSBhbiBpbmRleCBpbnRvIHRoZSBnYWluIHRhYmxlICovDQo+PiArCS8qIGFzc3VtZSBjbGVh ciBnbGFzcyBhcyBkZWZhdWx0ICovDQo+PiArCWNoaXAtPnRhb3Nfc2V0dGluZ3MuYWxzX2dhaW5f dHJpbSA9IDEwMDA7DQo+PiArCS8qIGRlZmF1bHQgZ2FpbiB0cmltIHRvIGFjY291bnQgZm9yIGFw ZXJ0dXJlIGVmZmVjdHMgKi8NCj4+ICsJY2hpcC0+dGFvc19zZXR0aW5ncy5hbHNfY2FsX3Rhcmdl dCA9IDEzMDsNCj4+ICsJLyogS25vd24gZXh0ZXJuYWwgQUxTIHJlYWRpbmcgdXNlZCBmb3IgY2Fs aWJyYXRpb24gKi8gfQ0KPj4gKw0KPiANCj4gLS0tLS0gc25pcCAtLS0tLS0tLS0tLS0NCj4+ICsJ aWYgKChjaDAgPj0gY2hpcC0+YWxzX3NhdHVyYXRpb24pIHx8IChjaDEgPj0gY2hpcC0+YWxzX3Nh dHVyYXRpb24pKQ0KPiB3b3VsZCBiZSBlYXNpZXIgdG8gcmVhZCBpZiB5b3Ugc2V0IHJldCB0byBs dXggbWF4IGhlcmUgYW4gYXZvaWQgDQo+IGp1bXBpbmcgaW50byB0aGUgaWYgc3RhdGVtZW50IGJl bG93Lg0KPiBOTyAtIFRTTDI1OFhfTFVYX0NBTENfT1ZFUl9GTE9XIE5FRURTIFRPIFBBU1NFRCBV UC4gIA0KPiAJTVVURVggTkVFRFMgVE8gQkUgVU5MT0NLRUQuIA0KPiAJVEhFTiBSRVRVUk4uDQpT b3JyeSwgc2hvdWxkIGhhdmUgc2FpZCBqdW1wIHRvIG91dF91bmxvY2sgaGF2aW5nIHNldCByZXQg PSBMVVhfQ0FMQ19PVkVSX0ZMT1c7DQoNCkp1c3QgbWFrZXMgZm9yIG1hcmdpbmFsbHkgY2xlYW5l ciBwcm9ncmFtIGZsb3cgdG8gbXkgbWluZCAodGhvdWdoIEkgZG9uJ3QgcmVhbGx5IGNhcmUgYWJv dXQgdGhpcyBvbmUpLg0KDQpJIFVOREVSU1RBTkQgQlVUIEkgRk9SR09UIFRPIE1FTlRJT04gVEhB VCBJTiBBRERJVElPTiBUTyBUSEUgQUJPVkUsIEFMU08gTkVFRFMgVE8gVVBEQVRFIFRIRSBBTFNf Q1VSX0lORk8gU1RSVUNULg0KU08sIEFMTCBTQUlEIC0gRUFTSUVSIFRPIFNJTVBMWSBKVU1QIFRP IFJFVFVSTl9NQVgsIEFTIFRISVMgSVMgQUxMIERPTkUgVEhFUkUuDQoNCj4+ICsJCWdvdG8gcmV0 dXJuX21heDsNCj4gDQo+IC0tLS0tIHNuaXAgLS0tLS0tLS0tLS0tDQo+ICZ0YW9zX2RldmljZV9s dXhbMF0gcGVyaGFwcz8NCj4gTk8gLSBDQVNUIE1BS0VTIElUIE1PUkUgT0JWSU9VUyAtIGF0IGxl YXN0IHRvIG1lIDstKQ0KPj4gKwlmb3IgKHAgPSAoc3RydWN0IHRhb3NfbHV4ICopIHRhb3NfZGV2 aWNlX2x1eDsNCj4gDQo+IC0tLS0tIHNuaXAgLS0tLS0tLS0tLS0tDQo+PiArDQo+IElmIG5vdCB0 aW1lIGNyaXRpY2FsIGxlc3QgbWFrZSB0aGF0IGEgc2xlZXAuDQo+IE5PIC0gVElNRSBJUyBSRVFV SVJFRCBGT1IgREVWSUNFIFRPIFNFVFRMRSBCRVRXRUVOIFBPV0VST04gQU5EIEFEQyBFTkFCTEUg LSBET04nVCBXQU5UIFRPIE1BS0UgSVQgQU5ZIExPTkdFUiBUSEFOIE5FQ0VTU0FSWS4NCkJ1dCBk byB5b3Ugd2FudCB0byBzcGluIHRoZSBwcm9jZXNzb3IgZHVyaW5nIHRoaXMgdGltZSBpbnN0ZWFk IG9mIGdldHRpbmcgb24gd2l0aCBzb21ldGhpbmcgdXNlZnVsPw0KSSBndWVzcyBpdCBkZXBlbmRz IG9uIGhvdyBjcml0aWNhbCBzcGVlZCBpcyBpbiB0aGUgdGFvc19jaGlwX29uIGZ1bmN0aW9uLiBJ J2Qgc2F5IHRoaXMgZGV2aWNlIGlzIHNsb3cgZW5vdWdoIHRoYXQgYSBwb3NzaWJsZSBleHRyYSBk ZWxheSBkb2Vzbid0IHJlYWxseSBtYXR0ZXIuDQo+PiArCW1kZWxheSgzKTsNCg0KQUdSRUVEIC0g Q0hBTkdFRCBUTyBNU0xFRVAoMyk7DQoNCg0KPj4gKwkvKiBOT1cgZW5hYmxlIHRoZSBBREMNCj4g DQo+IA0KPiAtLS0tLSBzbmlwIC0tLS0tLS0tLS0tLQ0KPiBJIHN0aWxsIHdvbmRlciBpZiB0aGVy ZSBpc24ndCBhIHdheSBvZiBhdm9pZGluZyB0aGlzIGluZGV4IGlzc3VlLg0KPiBJdCdzIGhvcnJp YmxlIGFuZCByZWFsbHkgZmVlbHMgbGlrZSBzb21ldGhpbmcgd2Ugb3VnaHQgdG8gYWJsZSB0byAN Cj4gaGFuZGxlIHJlYXNvbmFibHkgd2VsbC4uLg0KPiBCRUNBVVNFIFRIRSBDSDAgQU5EIENIMSBE SVZFUkdFIEFUIEhJR0ggR0FJTlMgLS0gSU5ERVggSVMgQkVUVEVSIFRIQU4gDQo+IFVTSU5HIENI TyBPUiBDSDEgVkFMVUUgKCBBUyBFSVRIRVIgT05FIE9WRVIgVEhFIE9USEVSIFdPVUxEIEJFIFdS T05HIA0KPiA6LXsgKQ0KSSBjYW4gc2VlIHlvdXIgcG9pbnQgdG8gYSBjZXJ0YWluIGV4dGVudC4g IFRoZSBjb3VudGVyIGFyZ3VtZW50IGlzIHRoYXQgZG9pbmcgaXQgd2l0aCBhbiBpbmRleCBwcmVj bHVkZXMgZXZlciB0b3VjaGluZyB0aGlzIHdpdGggYW55IHJlbW90ZWx5IGdlbmVyYWwgcHVycG9z ZSB1c2VyIHNwYWNlIGNvZGUuICBHaXZlbiBpdCdzIGFuIGludGVybmFsIGdhaW4gYW55d2F5IGlz IHRoZSBwcmVjaXNlIHZhbHVlIHRoYXQgY3JpdGljYWw/ICBCYXNpY2FsbHkgaXMgdXNlciBzcGFj ZSBldmVyIGdvaW5nIHRvIGNhcmUgYWJvdXQgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aG9zZSB0 aG9zZSB2YWx1ZXM/DQoNCkFub3RoZXIgb3B0aW9uIHdvdWxkIGJlIHRvIGhhdmUgYSBnYWluIGZv ciBlYWNoIGNoYW5uZWwgYXMgc2VwYXJhdGUgYXR0cmlidXRlcyAoY2xlYXJseSB3cml0aW5nIHRv IG9uZSB3b3VsZCBjaGFuZ2UgdGhlIG90aGVyKS4NCg0KSSBTRUUgWU9VUiBQT0lOVCBUT08gLSBC VVQgV0hBVCBFTFNFIENBTiBJIERPIChBU0lERSBGUk9NIEEgU0VQQVJBVEUgR0FJTiBGT1IgRUFD SCBDSEFOTkVMIC0gV0hJQ0ggV09VTEQgQkUgQ09ORlVTSU5HIFRPIE1BTkFHRSk/DQpJIEdVRVNT IEkgQ09VTEQgQlVDS0VUSVpFIEFOWVRISU5HID4gR0FJTiAxNiAtIEJVVCBUSEFUIFNFRU1TIFJB VEhFUiBLTFVER0VEPw0KQUdBSU4gU0VFTVMgTElLRSBNT1NUIFJFQVNPTkFCTEUgKEZPUiBOT1cg QU5ZV0FZKSBJUyBBTiBJTkRFWC4NCg0KDQo+PiArCWlmICh2YWx1ZSA+IDMpIHsNCj4+ICsJCWRl dl9lcnIoZGV2LCAiSW52YWxpZCBHYWluIEluZGV4OiBFbnRlciAwLTNcbiIpOw0KPj4gKwkJcmV0 dXJuIC0xOw0KPj4gKwl9IGVsc2Ugew0KPj4gKwkJY2hpcC0+dGFvc19zZXR0aW5ncy5hbHNfZ2Fp biA9IHZhbHVlOw0KPj4gKwl9DQo+PiArCXJldHVybiBsZW47DQo+PiArfQ0KPiANCj4gLS0tLS0g c25pcCAtLS0tLS0tLS0tLS0NCj4gSnVzdCB0byBjb25maXJtLCBpcyB0aGlzIGEgZnJlcXVlbmN5 IGluIEh6PyBJZiBpdCBpcyBjYW4gd2UgcmVuYW1pbmcgDQo+IGl0IHRvIHRhb3NfYWxzX2ZyZXF1 ZW5jeV9zaG93IHRvIGF2b2lkIGNvbmZ1c2luZyBtZT8NCj4gDQo+IFRISVMgSVMgVEhFIElOVEVS TkFMIEFMUyBJTlRFR1JBVElPTiBUSU1FIEZPUiBUSEUgQURDIENIQU5ORUxTIEkgU0hPRSANCj4g SE9STkVEIElUIElOVE8gU0FNUExJTkcgRlJFUVVFTkNZIFRPIEhFTFAgQUxFVklBVEUgVEhFIEFC SSBBTkdTVA0KVGhhdCdzIGdvb2QgYnV0IGl0IGRvZXMgaGF2ZSB0byBtYXRjaCB0aGUgdW5pdHMg c3BlY2lmaWVkIGluIHRoZSBBQkkgYXMgd2VsbC4NCg0KT0sgLSBNQVlCRSBJJ00gTUlTU0lORyBT T01FIElORk8uDQpBTEwgSSBIQVZFIEZPUiBUSEUgQUJJIElTIFRISVM6DQp3aGF0OgkJL3N5cy9i dXMvaWlvL2RldmljZXMvZGV2aWNlWC9zYW1wbGluZ19mcmVxdWVuY3kNCktlcm5lbFZlcnNpb246 CTIuNi4zNQ0KQ29udGFjdDoJbGludXgtaWlvQHZnZXIua2VybmVsLm9yZw0KRGVzY3JpcHRpb246 DQoJCVNvbWUgZGV2aWNlcyBoYXZlIGludGVybmFsIGNsb2Nrcy4gIFRoaXMgcGFyYW1ldGVyIHNl dHMgdGhlDQoJCXJlc3VsdGluZyBzYW1wbGluZyBmcmVxdWVuY3kuICBJbiBtYW55IGRldmljZXMg dGhpcw0KCQlwYXJhbWV0ZXIgaGFzIGFuIGVmZmVjdCBvbiBpbnB1dCBmaWx0ZXJzIGV0YyByYXRo ZXIgdGhhbg0KCQlzaW1wbHkgY29udHJvbGxpbmcgd2hlbiB0aGUgaW5wdXQgaXMgc2FtcGxlZC4g IEFzIHRoaXMNCgkJZWZmZWN0cyBkYXRhcmR5IHRyaWdnZXJzLCBoYXJkd2FyZSBidWZmZXJzIGFu ZCB0aGUgc3lzZnMNCgkJZGlyZWN0IGFjY2VzcyBpbnRlcmZhY2VzLCBpdCBtYXkgYmUgZm91bmQg aW4gYW55IG9mIHRoZQ0KCQlyZWxldmFudCBkaXJlY3Rvcmllcy4gIElmIGl0IGVmZmVjdHMgYWxs IG9mIHRoZSBhYm92ZQ0KCQl0aGVuIGl0IGlzIHRvIGJlIGZvdW5kIGluIHRoZSBiYXNlIGRldmlj ZSBkaXJlY3RvcnkgYXMgaGVyZS4NCg0KU08gSSBBTSBVTlNVUkUgT0YgV0hBVCBVTklUUyBORUVE IFRPIE1BVENIPw0KDQo+IA0KPj4gK3N0YXRpYyBzc2l6ZV90IHRhb3NfYWxzX3RpbWVfc2hvdyhz dHJ1Y3QgZGV2aWNlICpkZXYsDQo+PiArICAgIHN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRy LCBjaGFyICpidWYpIHsNCj4+ICsJc3RydWN0IGlpb19kZXYgKmluZGlvX2RldiA9IGRldl9nZXRf ZHJ2ZGF0YShkZXYpOw0KPj4gKwlzdHJ1Y3QgdHNsMjU4M19jaGlwICpjaGlwID0gaW5kaW9fZGV2 LT5kZXZfZGF0YTsNCj4+ICsNCj4+ICsJcmV0dXJuIHNwcmludGYoYnVmLCAiJWRcbiIsIGNoaXAt PnRhb3Nfc2V0dGluZ3MuYWxzX3RpbWUpOyB9DQo+IA0KPiAtLS0tLSBzbmlwIC0tLS0tLS0tLS0t LQ0KPiBzY2FsZSBhcyBhIHN0YW5kIGFsb25lIGF0dHJpYnV0ZSBpc24ndCBkZWZpbmVkLiBQbGVh c2UgZG9jdW1lbnQgdGhpcy4NCj4gTG9va2luZyBhdCB3aGF0IHlvdSBkbyB3aXRoIGl0LCBpdCdz IGFub3RoZXIgZmFjdG9yIGVmZmVjdGluZyB0aGUgDQo+IG92ZXJhbCBnYWluIG9uIHRoZSByZWFk aW5nIHRoYXQgcmVhY2hlcyB1c2Vyc3BhY2UuICBJZGVhbGx5IHlvdSdkIHJvbGwgDQo+IHRoaXMg aW50byB5b3VyIGNhbGlic2NhbGUgcGFyYW1ldGVyLCBidXQgSSBjYW4gc2VlIHRoYXQgd291bGQg Z2V0IA0KPiBjb21wbGV4IHRvIG1hbmFnZS4gV2lsbCBoYXZlIGEgdGhpbmsgYWJvdXQgdGhpcy4g SW4gZGV2aWNlcyB3aXRoIGEgDQo+IHNpbXBsZSBjb252ZXJzaW9uIGZ1bmN0aW9uIChhZGMncyBl dGMpIHdlIGhhbmRsZSB0aGlzIGJ5IGxlYXZpbmcgdGhpcyANCj4gc29mdHdhcmUgdmFsdWUgYmUg YXBwbGllZCBieSB1c2Vyc3BhY2UgKGFuZCBvdXRwdXQgaXQgYXMgaW5fc2NhbGUpLiANCj4gVGhl IGlzc3VlIGhlcmUgdGhhdCBhcyBmYXIgYXMgdXNlcnNwYWNlIGlzIGNvbmNlcm5lZCBib3RoIG9m IHlvdXIgDQo+IHNjYWxlcyBoYXZlIGJlZW4gYXBwbGllZCBiZWZvcmUgaXQgc2VlcyB0aGUgZGF0 YSBhbmQgYXQgZGlmZmVyZW50IG1vcmUgDQo+IG9yIGxlc3MgcmFuZG9tIGxvb2tpbmcgcG9pbnRz IGluIHRoZSBjYWxjdWxhdGlvbi4NCj4gDQo+IEFjdHVhbGx5LCBsb29raW5nIGF0IHRoZSBjYWxj dWxhdGlvbiB5b3UgY291bGQgb3V0cHV0IGlsbHVtaW5hbmNlMF9yYXcgDQo+IGFuZCBsZXQgdXNl cnNwYWNlIGFwcGx5IGEgbXVsdGlwbGllciBiYXNlZCBvbiB5b3VyIHRyaW0gdmFsdWUgYW5kIA0K PiBvZmZzZXQNCj4gKzAuNT8gIElmIHlvdSB3YW50IHRvIGhvbGQgdHJpbSBpbiBkcml2ZXIgdGhl biBqdXN0IGltcGxlbWVudA0KPiByZWFkIGFuZCB3cml0ZSB0bw0KPiANCj4gaWxsdW1pbmFuY2Uw X3NjYWxlDQo+IGFuZCBoYXZlIHJlYWQgb25seQ0KPiBpbGx1bWluYW5jZTBfb2Zmc2V0IChyYXRo ZXIgdGVkaW91c2x5IGZvciB0aGlzIGRldmljZSwgb2Zmc2V0IGlzIA0KPiBhcHBsaWVkIGJlZm9y ZSBzY2FsZSwgc28geW91J2xsIG5lZWQgdG8gZGl2aWRlIDAuNSBieSB3aGF0ZXZlciB5b3VyIHRy aW0gaXMpLg0KPiANCj4gV2UnbGwgaGF2ZSB0byBkbyBwaW4gZG93biBob3cgdG8gZG8gdGhpcyBi ZWZvcmUgbW92aW5nIG91dCBvZiBzdGFnaW5nIA0KPiBzbyBiZXN0IHRvIGdldCBpdCByaWdodCBu b3cuDQo+IA0KPiBDSEFOR0VEIFRPIElMTFVNSU5BTkNFMF9TQ0FMRQ0KPiANCj4gTElGRSBXT1VM RSBCRSBOSUNFIElGIFdFIENPVUxEIEpVU1QgUEFTUyBUSEUgUkFXIERBVEEgVVAgVE8gVVNFUlNQ QUNFIA0KPiBCVVQgV0UgSEFWRSBDVVNUT01FUlMgV0hPIFJFUVVJUkUgSVQgVE8gQ09NRSBVUCBD QUxDVUxBVEVEIFdJVEggVEhFIA0KPiBNVUxUSVBMSUVSIEZBQ1RPUkVEIElODQpTdXJlLiBJdCdz IGEgZmlkZGx5IGNhbGN1bGF0aW9uIHNvIEkgY2FuIGtpbmQgb2Ygc2VlIHRoZWlyIHBvaW50Lg0K VGhlc2UgbGlnaHQgc2Vuc29ycyBhcmUgYWxsIGEgcGFpbiA6KQ0KU08gLSBXRSBBUkUgT0s/DQo+ IA0KPiAtLS0tLSBzbmlwIC0tLS0tLS0tLS0tLQ0KPj4gKwlmb3IgKGkgPSAwOyBpIDwgTUFYX0RF VklDRV9SRUdTOyBpKyspIHsNCj4+ICsJCXJldCA9IGkyY19zbWJ1c193cml0ZV9ieXRlKGNsaWVu dHAsDQo+PiArCQkJCShUU0wyNThYX0NNRF9SRUcgfCAoVFNMMjU4WF9DTlRSTCArIGkpKSk7DQo+ PiArCQlpZiAocmV0IDwgMCkgew0KPj4gKwkJCWRldl9lcnIoJmNsaWVudHAtPmRldiwgImkyY19z bWJ1c193cml0ZV9ieXRlKCkgdG8gY21kICINCj4+ICsJCQkJInJlZyBmYWlsZWQgaW4gdGFvc19w cm9iZSgpLCBlcnIgPSAlZFxuIiwgcmV0KTsNCj4+ICsJCQlnb3RvIGZhaWwxOw0KPj4gKwkJfQ0K Pj4gKwkJYnVmW2ldID0gaTJjX3NtYnVzX3JlYWRfYnl0ZShjbGllbnRwKTsNCj4gICBlcnJvciBo YW5kbGluZyBmb3IgdGhpcyByZWFkPw0KPiBWQUxVRSBJUyBVTklNUE9SVEFOVCAtIEJVVCBNQUtJ TkcgU1VSRSBXRSBDQU4gSlVTVCBSRUFEIEFMTCAzMiBSRUdJU1RFUiBMT0NBVElPTlMgSVMuLg0K PiANCj4gLS0tLS0gc25pcCAtLS0tLS0tLS0tLS0NCj4gDQo+PiArCX0NCj4+ICsJaWYgKCF0YW9z X3NrYXRlX2RldmljZShidWYpKSB7DQo+PiArCQlkZXZfaW5mbygmY2xpZW50cC0+ZGV2LCAiaTJj IGRldmljZSBmb3VuZCBidXQgZG9lcyBub3QgbWF0Y2ggIg0KPj4gKwkJCSJleHBlY3RlZCBpZCBp biB0YW9zX3Byb2JlKClcbiIpOw0KPj4gKwkJZ290byBmYWlsMTsNCj4+ICsJfSBlbHNlIHsNCj4g VGhlIHNvcnQgb2YgZGVidWcgaW5mbyB5b3Ugd2FudCB0byBnZXQgcmlkIG9mIGZvciBwcm9kdWN0 aW9uIGRyaXZlcnMuICANCj4gRG9lc24ndCB0ZWxsIGFueW9uZSBhbnl0aGluZyBoZWxwZnVsLg0K PiBOTyAtIERPIE5PVCBBR1JFRSAtIElGIEEgQ1VTVE9NRVIgRVhQRUNUUyBPTkUgREVWSUNFIEJV VCBIQVMgU09NRUhPVyANCj4gSU5TVEFMTEVEIEEgRElGRkVSRU5UIE9ORSBBVCBQUk9EVUNUSU9O IFRJTUUsIFRISVMgV0lMTCBIRUxQIElERU5USUZZIFRIRSBJU1NVRS4NCj4gKElFLiBXQU5URUQg QSBUQU9TIEFMUyBERVZJQ0UgQlVUIElOU1RBTExFRCBBIFRBT1MgUFJPWC9BTFMgREVWSUNFKSAN Cj4gRklSU1QgUEFSVCBJTkRJQ0FURVMgVEhBVC4gIFNFQ09ORCBQQVJUIElTIENPTkZJUk1BVElP TiBUSEFUIERFVklDRSBXQVMgSURFTlRJRklFRCBUTyBTWVNURU0uDQoNCkknbSBoYXBweSB3aXRo IHRoZSBlcnJvciBvbmUuIEp1c3QgZG9uJ3Qgc2VlIHRoZSBwb2ludCBpbiBzYXlpbmcgJ2V2ZXJ5 dGhpbmcgaXMgYXMgZXhwZWN0ZWQnLg0KVGhlIG1lcmUgYWJzZW5jZSBvZiB0aGUgZXJyb3IgaW5k aWNhdGVzIHRoYXQganVzdCBmaW5lIQ0KQUdSRUVEIC0gUkVNT1ZFRCAyTkQgUEFSVCAoVEhFIE9L IE1FU1NBR0UpDQoNCkpvbmF0aGFuDQoNCg== ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver 2011-03-23 22:38 ` Jon Brenner @ 2011-03-24 11:15 ` Jonathan Cameron 2011-03-24 19:04 ` Jon Brenner 0 siblings, 1 reply; 10+ messages in thread From: Jonathan Cameron @ 2011-03-24 11:15 UTC (permalink / raw) To: Jon Brenner; +Cc: linux-iio, linux-kernel On 03/23/11 22:38, Jon Brenner wrote: > Hi Jonathan, > Below are a few comments/questions to your latest response. > Any direction is greatly appreciated. > > Jon No chance you can persuade your email client to do conventional indenting? Ah well, I guess this works more or less. >> >> ----- snip ------------ >>> + if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) >> would be easier to read if you set ret to lux max here an avoid >> jumping into the if statement below. >> NO - TSL258X_LUX_CALC_OVER_FLOW NEEDS TO PASSED UP. >> MUTEX NEEDS TO BE UNLOCKED. >> THEN RETURN. > Sorry, should have said jump to out_unlock having set ret = LUX_CALC_OVER_FLOW; > > Just makes for marginally cleaner program flow to my mind (though I don't really care about this one). > > I UNDERSTAND BUT I FORGOT TO MENTION THAT IN ADDITION TO THE ABOVE, ALSO NEEDS TO UPDATE THE ALS_CUR_INFO STRUCT. > SO, ALL SAID - EASIER TO SIMPLY JUMP TO RETURN_MAX, AS THIS IS ALL DONE THERE. Fair enough. Was just personal preference anyway! ... > >>> + /* NOW enable the ADC >> >> >> ----- snip ------------ >> I still wonder if there isn't a way of avoiding this index issue. >> It's horrible and really feels like something we ought to able to >> handle reasonably well... >> BECAUSE THE CH0 AND CH1 DIVERGE AT HIGH GAINS -- INDEX IS BETTER THAN >> USING CHO OR CH1 VALUE ( AS EITHER ONE OVER THE OTHER WOULD BE WRONG >> :-{ ) > I can see your point to a certain extent. The counter argument is that doing it with an index precludes ever touching this with any remotely general purpose user space code. Given it's an internal gain anyway is the precise value that critical? Basically is user space ever going to care about the difference between those those values? > > Another option would be to have a gain for each channel as separate attributes (clearly writing to one would change the other). > > I SEE YOUR POINT TOO - BUT WHAT ELSE CAN I DO (ASIDE FROM A SEPARATE GAIN FOR EACH CHANNEL - WHICH WOULD BE CONFUSING TO MANAGE)? > I GUESS I COULD BUCKETIZE ANYTHING > GAIN 16 - BUT THAT SEEMS RATHER KLUDGED? > AGAIN SEEMS LIKE MOST REASONABLE (FOR NOW ANYWAY) IS AN INDEX. It may be reasonable, but it isn't generalizable which means it probably isn't viable long term. The parameter simply won't be used by anything that isn't custom coded for this particular sensor. Even Taos' next generation of sensors probably won't have an index which has the same effect. If it can be coherently blugeoned into existing interfaces, then we should do so. There are quite a few other bits of IIO interface where changing one value will effect others. This means (and we could emphasise it more) that there are sets of values user space MUST check after making a given change if it wants to know the full device state. Believe me, things are much more complex with devices that do partial scans of channels only in some combinations! >> Just to confirm, is this a frequency in Hz? If it is can we renaming >> it to taos_als_frequency_show to avoid confusing me? >> >> THIS IS THE INTERNAL ALS INTEGRATION TIME FOR THE ADC CHANNELS I SHOE >> HORNED IT INTO SAMPLING FREQUENCY TO HELP ALEVIATE THE ABI ANGST > That's good but it does have to match the units specified in the ABI as well. > > OK - MAYBE I'M MISSING SOME INFO. > ALL I HAVE FOR THE ABI IS THIS: > what: /sys/bus/iio/devices/deviceX/sampling_frequency > KernelVersion: 2.6.35 > Contact: linux-iio@vger.kernel.org > Description: > Some devices have internal clocks. This parameter sets the > resulting sampling frequency. In many devices this > parameter has an effect on input filters etc rather than > simply controlling when the input is sampled. As this > effects datardy triggers, hardware buffers and the sysfs > direct access interfaces, it may be found in any of the > relevant directories. If it effects all of the above > then it is to be found in the base device directory as here. > > SO I AM UNSURE OF WHAT UNITS NEED TO MATCH? Fair point. That documentation is clearly lacking. One for the TODO list. Anyhow, it does say sampling frequency so the units can't be a measure of time. What it should say is 'in Hz' somewhere. > >> >>> +static ssize_t taos_als_time_show(struct device *dev, >>> + struct device_attribute *attr, char *buf) { >>> + struct iio_dev *indio_dev = dev_get_drvdata(dev); >>> + struct tsl2583_chip *chip = indio_dev->dev_data; >>> + >>> + return sprintf(buf, "%d\n", chip->taos_settings.als_time); } >> >> ----- snip ------------ >> scale as a stand alone attribute isn't defined. Please document this. >> Looking at what you do with it, it's another factor effecting the >> overal gain on the reading that reaches userspace. Ideally you'd roll >> this into your calibscale parameter, but I can see that would get >> complex to manage. Will have a think about this. In devices with a >> simple conversion function (adc's etc) we handle this by leaving this >> software value be applied by userspace (and output it as in_scale). >> The issue here that as far as userspace is concerned both of your >> scales have been applied before it sees the data and at different more >> or less random looking points in the calculation. >> >> Actually, looking at the calculation you could output illuminance0_raw >> and let userspace apply a multiplier based on your trim value and >> offset >> +0.5? If you want to hold trim in driver then just implement >> read and write to >> >> illuminance0_scale >> and have read only >> illuminance0_offset (rather tediously for this device, offset is >> applied before scale, so you'll need to divide 0.5 by whatever your trim is). >> >> We'll have to do pin down how to do this before moving out of staging >> so best to get it right now. >> >> CHANGED TO ILLUMINANCE0_SCALE >> >> LIFE WOULE BE NICE IF WE COULD JUST PASS THE RAW DATA UP TO USERSPACE >> BUT WE HAVE CUSTOMERS WHO REQUIRE IT TO COME UP CALCULATED WITH THE >> MULTIPLIER FACTORED IN > Sure. It's a fiddly calculation so I can kind of see their point. > These light sensors are all a pain :) > SO - WE ARE OK? Err. I've kind of lost track, but I think so. Will take one last look at your next revision! Sounds like it may have some interesting new features anyway given the other thread! >> >> ----- snip ------------ >>> + for (i = 0; i < MAX_DEVICE_REGS; i++) { >>> + ret = i2c_smbus_write_byte(clientp, >>> + (TSL258X_CMD_REG | (TSL258X_CNTRL + i))); >>> + if (ret < 0) { >>> + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd " >>> + "reg failed in taos_probe(), err = %d\n", ret); >>> + goto fail1; >>> + } >>> + buf[i] = i2c_smbus_read_byte(clientp); >> error handling for this read? >> VALUE IS UNIMPORTANT - BUT MAKING SURE WE CAN JUST READ ALL 32 REGISTER LOCATIONS IS.. That's fine, but you haven't verified that if you don't check for a negative return from that read. >> >> ----- snip ------------ >> >>> + } >>> + if (!taos_skate_device(buf)) { >>> + dev_info(&clientp->dev, "i2c device found but does not match " >>> + "expected id in taos_probe()\n"); >>> + goto fail1; >>> + } else { >> The sort of debug info you want to get rid of for production drivers. >> Doesn't tell anyone anything helpful. >> NO - DO NOT AGREE - IF A CUSTOMER EXPECTS ONE DEVICE BUT HAS SOMEHOW >> INSTALLED A DIFFERENT ONE AT PRODUCTION TIME, THIS WILL HELP IDENTIFY THE ISSUE. >> (IE. WANTED A TAOS ALS DEVICE BUT INSTALLED A TAOS PROX/ALS DEVICE) >> FIRST PART INDICATES THAT. SECOND PART IS CONFIRMATION THAT DEVICE WAS IDENTIFIED TO SYSTEM. > > I'm happy with the error one. Just don't see the point in saying 'everything is as expected'. > The mere absence of the error indicates that just fine! > AGREED - REMOVED 2ND PART (THE OK MESSAGE) Cool Coming together nicely. Jonathan ^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver 2011-03-24 11:15 ` Jonathan Cameron @ 2011-03-24 19:04 ` Jon Brenner 2011-03-24 20:10 ` Jonathan Cameron 0 siblings, 1 reply; 10+ messages in thread From: Jon Brenner @ 2011-03-24 19:04 UTC (permalink / raw) To: Jonathan Cameron; +Cc: linux-iio, linux-kernel Hi Jonathan, The remaining issue that I am still trying to resolve is dealing with a proper ABI for the device integration time. If 'illuminance0_sampling_frequency' is not the proper ABI, should I create a new ABI called illuminance0_integration_time and add it to the sys-bus-iio-lisgt-tsl2583 document as you had me do with /sys/bus/iio/devices/device[n]/lux_table? Jon -----Original Message----- From: Jonathan Cameron [mailto:jic23@cam.ac.uk] Sent: Thursday, March 24, 2011 6:16 AM To: Jon Brenner Cc: linux-iio@vger.kernel.org; linux-kernel@vger.kernel.org Subject: Re: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver On 03/23/11 22:38, Jon Brenner wrote: > Hi Jonathan, > Below are a few comments/questions to your latest response. > Any direction is greatly appreciated. > > Jon No chance you can persuade your email client to do conventional indenting? Ah well, I guess this works more or less. >> >> ----- snip ------------ >>> + if ((ch0 >= chip->als_saturation) || (ch1 >= >>> +chip->als_saturation)) >> would be easier to read if you set ret to lux max here an avoid >> jumping into the if statement below. >> NO - TSL258X_LUX_CALC_OVER_FLOW NEEDS TO PASSED UP. >> MUTEX NEEDS TO BE UNLOCKED. >> THEN RETURN. > Sorry, should have said jump to out_unlock having set ret = > LUX_CALC_OVER_FLOW; > > Just makes for marginally cleaner program flow to my mind (though I don't really care about this one). > > I UNDERSTAND BUT I FORGOT TO MENTION THAT IN ADDITION TO THE ABOVE, ALSO NEEDS TO UPDATE THE ALS_CUR_INFO STRUCT. > SO, ALL SAID - EASIER TO SIMPLY JUMP TO RETURN_MAX, AS THIS IS ALL DONE THERE. Fair enough. Was just personal preference anyway! ... > >>> + /* NOW enable the ADC >> >> >> ----- snip ------------ >> I still wonder if there isn't a way of avoiding this index issue. >> It's horrible and really feels like something we ought to able to >> handle reasonably well... >> BECAUSE THE CH0 AND CH1 DIVERGE AT HIGH GAINS -- INDEX IS BETTER THAN >> USING CHO OR CH1 VALUE ( AS EITHER ONE OVER THE OTHER WOULD BE WRONG >> :-{ ) > I can see your point to a certain extent. The counter argument is that doing it with an index precludes ever touching this with any remotely general purpose user space code. Given it's an internal gain anyway is the precise value that critical? Basically is user space ever going to care about the difference between those those values? > > Another option would be to have a gain for each channel as separate attributes (clearly writing to one would change the other). > > I SEE YOUR POINT TOO - BUT WHAT ELSE CAN I DO (ASIDE FROM A SEPARATE GAIN FOR EACH CHANNEL - WHICH WOULD BE CONFUSING TO MANAGE)? > I GUESS I COULD BUCKETIZE ANYTHING > GAIN 16 - BUT THAT SEEMS RATHER KLUDGED? > AGAIN SEEMS LIKE MOST REASONABLE (FOR NOW ANYWAY) IS AN INDEX. It may be reasonable, but it isn't generalizable which means it probably isn't viable long term. The parameter simply won't be used by anything that isn't custom coded for this particular sensor. Even Taos' next generation of sensors probably won't have an index which has the same effect. If it can be coherently blugeoned into existing interfaces, then we should do so. There are quite a few other bits of IIO interface where changing one value will effect others. This means (and we could emphasise it more) that there are sets of values user space MUST check after making a given change if it wants to know the full device state. Believe me, things are much more complex with devices that do partial scans of channels only in some combinations! >> Just to confirm, is this a frequency in Hz? If it is can we renaming >> it to taos_als_frequency_show to avoid confusing me? >> >> THIS IS THE INTERNAL ALS INTEGRATION TIME FOR THE ADC CHANNELS I SHOE >> HORNED IT INTO SAMPLING FREQUENCY TO HELP ALEVIATE THE ABI ANGST > That's good but it does have to match the units specified in the ABI as well. > > OK - MAYBE I'M MISSING SOME INFO. > ALL I HAVE FOR THE ABI IS THIS: > what: /sys/bus/iio/devices/deviceX/sampling_frequency > KernelVersion: 2.6.35 > Contact: linux-iio@vger.kernel.org > Description: > Some devices have internal clocks. This parameter sets the > resulting sampling frequency. In many devices this > parameter has an effect on input filters etc rather than > simply controlling when the input is sampled. As this > effects datardy triggers, hardware buffers and the sysfs > direct access interfaces, it may be found in any of the > relevant directories. If it effects all of the above > then it is to be found in the base device directory as here. > > SO I AM UNSURE OF WHAT UNITS NEED TO MATCH? Fair point. That documentation is clearly lacking. One for the TODO list. Anyhow, it does say sampling frequency so the units can't be a measure of time. What it should say is 'in Hz' somewhere. > >> >>> +static ssize_t taos_als_time_show(struct device *dev, >>> + struct device_attribute *attr, char *buf) { >>> + struct iio_dev *indio_dev = dev_get_drvdata(dev); >>> + struct tsl2583_chip *chip = indio_dev->dev_data; >>> + >>> + return sprintf(buf, "%d\n", chip->taos_settings.als_time); } >> >> ----- snip ------------ >> scale as a stand alone attribute isn't defined. Please document this. >> Looking at what you do with it, it's another factor effecting the >> overal gain on the reading that reaches userspace. Ideally you'd >> roll this into your calibscale parameter, but I can see that would >> get complex to manage. Will have a think about this. In devices with >> a simple conversion function (adc's etc) we handle this by leaving >> this software value be applied by userspace (and output it as in_scale). >> The issue here that as far as userspace is concerned both of your >> scales have been applied before it sees the data and at different >> more or less random looking points in the calculation. >> >> Actually, looking at the calculation you could output >> illuminance0_raw and let userspace apply a multiplier based on your >> trim value and offset >> +0.5? If you want to hold trim in driver then just implement >> read and write to >> >> illuminance0_scale >> and have read only >> illuminance0_offset (rather tediously for this device, offset is >> applied before scale, so you'll need to divide 0.5 by whatever your trim is). >> >> We'll have to do pin down how to do this before moving out of staging >> so best to get it right now. >> >> CHANGED TO ILLUMINANCE0_SCALE >> >> LIFE WOULE BE NICE IF WE COULD JUST PASS THE RAW DATA UP TO USERSPACE >> BUT WE HAVE CUSTOMERS WHO REQUIRE IT TO COME UP CALCULATED WITH THE >> MULTIPLIER FACTORED IN > Sure. It's a fiddly calculation so I can kind of see their point. > These light sensors are all a pain :) > SO - WE ARE OK? Err. I've kind of lost track, but I think so. Will take one last look at your next revision! Sounds like it may have some interesting new features anyway given the other thread! >> >> ----- snip ------------ >>> + for (i = 0; i < MAX_DEVICE_REGS; i++) { >>> + ret = i2c_smbus_write_byte(clientp, >>> + (TSL258X_CMD_REG | (TSL258X_CNTRL + i))); >>> + if (ret < 0) { >>> + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd " >>> + "reg failed in taos_probe(), err = %d\n", ret); >>> + goto fail1; >>> + } >>> + buf[i] = i2c_smbus_read_byte(clientp); >> error handling for this read? >> VALUE IS UNIMPORTANT - BUT MAKING SURE WE CAN JUST READ ALL 32 REGISTER LOCATIONS IS.. That's fine, but you haven't verified that if you don't check for a negative return from that read. AGREED - ADDED CHECK FOR NEGATIVE RETURN >> >> ----- snip ------------ >> >>> + } >>> + if (!taos_skate_device(buf)) { >>> + dev_info(&clientp->dev, "i2c device found but does not match " >>> + "expected id in taos_probe()\n"); >>> + goto fail1; >>> + } else { >> The sort of debug info you want to get rid of for production drivers. >> Doesn't tell anyone anything helpful. >> NO - DO NOT AGREE - IF A CUSTOMER EXPECTS ONE DEVICE BUT HAS SOMEHOW >> INSTALLED A DIFFERENT ONE AT PRODUCTION TIME, THIS WILL HELP IDENTIFY THE ISSUE. >> (IE. WANTED A TAOS ALS DEVICE BUT INSTALLED A TAOS PROX/ALS DEVICE) >> FIRST PART INDICATES THAT. SECOND PART IS CONFIRMATION THAT DEVICE WAS IDENTIFIED TO SYSTEM. > > I'm happy with the error one. Just don't see the point in saying 'everything is as expected'. > The mere absence of the error indicates that just fine! > AGREED - REMOVED 2ND PART (THE OK MESSAGE) Cool Coming together nicely. Jonathan ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver 2011-03-24 19:04 ` Jon Brenner @ 2011-03-24 20:10 ` Jonathan Cameron 0 siblings, 0 replies; 10+ messages in thread From: Jonathan Cameron @ 2011-03-24 20:10 UTC (permalink / raw) To: Jon Brenner; +Cc: linux-iio, linux-kernel On 03/24/11 19:04, Jon Brenner wrote: > Hi Jonathan, > The remaining issue that I am still trying to resolve is dealing with a > proper ABI for the device integration time. > If 'illuminance0_sampling_frequency' is not the proper ABI, should I > create a new ABI > called illuminance0_integration_time and add it to the > sys-bus-iio-lisgt-tsl2583 document as you had me do with > /sys/bus/iio/devices/device[n]/lux_table? Hmm. It really isn't fitting well in sampling frequency is it? Obviously it is connected to the frequency at which one can sample, but isn't quite the same. Throw an email to linux-iio proposing such an attribute and lets see what people come back with. This sort of integration time is pretty specific to light sensors so for now add it to the light docs - it is however a general thing on light sensors so we want something that isn't device specific. Make sure it is in sensible units though (seconds). > > Jon > -----Original Message----- > From: Jonathan Cameron [mailto:jic23@cam.ac.uk] > Sent: Thursday, March 24, 2011 6:16 AM > To: Jon Brenner > Cc: linux-iio@vger.kernel.org; linux-kernel@vger.kernel.org > Subject: Re: [PATCH 2.6.38-rc7]TAOS 258x: Device Driver > > On 03/23/11 22:38, Jon Brenner wrote: >> Hi Jonathan, >> Below are a few comments/questions to your latest response. >> Any direction is greatly appreciated. >> >> Jon > No chance you can persuade your email client to do conventional > indenting? Ah well, I guess this works more or less. > >>> >>> ----- snip ------------ >>>> + if ((ch0 >= chip->als_saturation) || (ch1 >= >>>> +chip->als_saturation)) >>> would be easier to read if you set ret to lux max here an avoid >>> jumping into the if statement below. >>> NO - TSL258X_LUX_CALC_OVER_FLOW NEEDS TO PASSED UP. >>> MUTEX NEEDS TO BE UNLOCKED. >>> THEN RETURN. >> Sorry, should have said jump to out_unlock having set ret = >> LUX_CALC_OVER_FLOW; >> >> Just makes for marginally cleaner program flow to my mind (though I > don't really care about this one). >> >> I UNDERSTAND BUT I FORGOT TO MENTION THAT IN ADDITION TO THE ABOVE, > ALSO NEEDS TO UPDATE THE ALS_CUR_INFO STRUCT. >> SO, ALL SAID - EASIER TO SIMPLY JUMP TO RETURN_MAX, AS THIS IS ALL > DONE THERE. > Fair enough. Was just personal preference anyway! > ... >> >>>> + /* NOW enable the ADC >>> >>> >>> ----- snip ------------ >>> I still wonder if there isn't a way of avoiding this index issue. >>> It's horrible and really feels like something we ought to able to >>> handle reasonably well... >>> BECAUSE THE CH0 AND CH1 DIVERGE AT HIGH GAINS -- INDEX IS BETTER THAN > >>> USING CHO OR CH1 VALUE ( AS EITHER ONE OVER THE OTHER WOULD BE WRONG >>> :-{ ) >> I can see your point to a certain extent. The counter argument is > that doing it with an index precludes ever touching this with any > remotely general purpose user space code. Given it's an internal gain > anyway is the precise value that critical? Basically is user space ever > going to care about the difference between those those values? >> >> Another option would be to have a gain for each channel as separate > attributes (clearly writing to one would change the other). >> >> I SEE YOUR POINT TOO - BUT WHAT ELSE CAN I DO (ASIDE FROM A SEPARATE > GAIN FOR EACH CHANNEL - WHICH WOULD BE CONFUSING TO MANAGE)? >> I GUESS I COULD BUCKETIZE ANYTHING > GAIN 16 - BUT THAT SEEMS RATHER > KLUDGED? >> AGAIN SEEMS LIKE MOST REASONABLE (FOR NOW ANYWAY) IS AN INDEX. > It may be reasonable, but it isn't generalizable which means it probably > isn't viable long term. The parameter simply won't be used by anything > that isn't custom coded > for this particular sensor. Even Taos' next generation of sensors > probably won't > have an index which has the same effect. > > If it can be coherently blugeoned into existing interfaces, then we > should do so. > There are quite a few other bits of IIO interface where changing one > value will effect others. This means (and we could emphasise it more) > that there are sets of values user space MUST check after making a given > change if it wants to know the full device state. Believe me, things > are much more complex with devices that do partial scans of channels > only in some combinations! > >>> Just to confirm, is this a frequency in Hz? If it is can we renaming >>> it to taos_als_frequency_show to avoid confusing me? >>> >>> THIS IS THE INTERNAL ALS INTEGRATION TIME FOR THE ADC CHANNELS I SHOE > >>> HORNED IT INTO SAMPLING FREQUENCY TO HELP ALEVIATE THE ABI ANGST >> That's good but it does have to match the units specified in the ABI > as well. >> >> OK - MAYBE I'M MISSING SOME INFO. >> ALL I HAVE FOR THE ABI IS THIS: >> what: /sys/bus/iio/devices/deviceX/sampling_frequency >> KernelVersion: 2.6.35 >> Contact: linux-iio@vger.kernel.org >> Description: >> Some devices have internal clocks. This parameter sets > the >> resulting sampling frequency. In many devices this >> parameter has an effect on input filters etc rather than >> simply controlling when the input is sampled. As this >> effects datardy triggers, hardware buffers and the sysfs >> direct access interfaces, it may be found in any of the >> relevant directories. If it effects all of the above >> then it is to be found in the base device directory as > here. >> >> SO I AM UNSURE OF WHAT UNITS NEED TO MATCH? > Fair point. That documentation is clearly lacking. One for the TODO > list. > Anyhow, it does say sampling frequency so the units can't be a measure > of time. What it should say is 'in Hz' somewhere. >> >>> >>>> +static ssize_t taos_als_time_show(struct device *dev, >>>> + struct device_attribute *attr, char *buf) { >>>> + struct iio_dev *indio_dev = dev_get_drvdata(dev); >>>> + struct tsl2583_chip *chip = indio_dev->dev_data; >>>> + >>>> + return sprintf(buf, "%d\n", chip->taos_settings.als_time); } >>> >>> ----- snip ------------ >>> scale as a stand alone attribute isn't defined. Please document this. >>> Looking at what you do with it, it's another factor effecting the >>> overal gain on the reading that reaches userspace. Ideally you'd >>> roll this into your calibscale parameter, but I can see that would >>> get complex to manage. Will have a think about this. In devices with >>> a simple conversion function (adc's etc) we handle this by leaving >>> this software value be applied by userspace (and output it as > in_scale). >>> The issue here that as far as userspace is concerned both of your >>> scales have been applied before it sees the data and at different >>> more or less random looking points in the calculation. >>> >>> Actually, looking at the calculation you could output >>> illuminance0_raw and let userspace apply a multiplier based on your >>> trim value and offset >>> +0.5? If you want to hold trim in driver then just implement >>> read and write to >>> >>> illuminance0_scale >>> and have read only >>> illuminance0_offset (rather tediously for this device, offset is >>> applied before scale, so you'll need to divide 0.5 by whatever your > trim is). >>> >>> We'll have to do pin down how to do this before moving out of staging > >>> so best to get it right now. >>> >>> CHANGED TO ILLUMINANCE0_SCALE >>> >>> LIFE WOULE BE NICE IF WE COULD JUST PASS THE RAW DATA UP TO USERSPACE > >>> BUT WE HAVE CUSTOMERS WHO REQUIRE IT TO COME UP CALCULATED WITH THE >>> MULTIPLIER FACTORED IN >> Sure. It's a fiddly calculation so I can kind of see their point. >> These light sensors are all a pain :) >> SO - WE ARE OK? > Err. I've kind of lost track, but I think so. Will take one last look > at your next revision! Sounds like it may have some interesting new > features anyway given the other thread! >>> >>> ----- snip ------------ >>>> + for (i = 0; i < MAX_DEVICE_REGS; i++) { >>>> + ret = i2c_smbus_write_byte(clientp, >>>> + (TSL258X_CMD_REG | (TSL258X_CNTRL + > i))); >>>> + if (ret < 0) { >>>> + dev_err(&clientp->dev, "i2c_smbus_write_byte() > to cmd " >>>> + "reg failed in taos_probe(), err = > %d\n", ret); >>>> + goto fail1; >>>> + } >>>> + buf[i] = i2c_smbus_read_byte(clientp); >>> error handling for this read? >>> VALUE IS UNIMPORTANT - BUT MAKING SURE WE CAN JUST READ ALL 32 > REGISTER LOCATIONS IS.. > That's fine, but you haven't verified that if you don't check for a > negative return from that read. > > AGREED - ADDED CHECK FOR NEGATIVE RETURN > >>> >>> ----- snip ------------ >>> >>>> + } >>>> + if (!taos_skate_device(buf)) { >>>> + dev_info(&clientp->dev, "i2c device found but does not > match " >>>> + "expected id in taos_probe()\n"); >>>> + goto fail1; >>>> + } else { >>> The sort of debug info you want to get rid of for production drivers. > >>> Doesn't tell anyone anything helpful. >>> NO - DO NOT AGREE - IF A CUSTOMER EXPECTS ONE DEVICE BUT HAS SOMEHOW >>> INSTALLED A DIFFERENT ONE AT PRODUCTION TIME, THIS WILL HELP IDENTIFY > THE ISSUE. >>> (IE. WANTED A TAOS ALS DEVICE BUT INSTALLED A TAOS PROX/ALS DEVICE) >>> FIRST PART INDICATES THAT. SECOND PART IS CONFIRMATION THAT DEVICE > WAS IDENTIFIED TO SYSTEM. >> >> I'm happy with the error one. Just don't see the point in saying > 'everything is as expected'. >> The mere absence of the error indicates that just fine! >> AGREED - REMOVED 2ND PART (THE OK MESSAGE) > Cool > > Coming together nicely. > > Jonathan > -- > To unsubscribe from this list: send the line "unsubscribe linux-iio" 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] 10+ messages in thread
end of thread, other threads:[~2011-03-24 20:09 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1299634342.1785.20.camel@jonz-ubuntu>
2011-03-09 19:14 ` [PATCH 2.6.38-rc7]TAOS 258x: Device Driver Jonathan Cameron
2011-03-12 1:16 ` Jon Brenner
2011-03-14 19:45 Jon Brenner
2011-03-21 19:07 ` Jonathan Cameron
2011-03-23 1:07 ` Jon Brenner
2011-03-23 11:06 ` Jonathan Cameron
2011-03-23 22:38 ` Jon Brenner
2011-03-24 11:15 ` Jonathan Cameron
2011-03-24 19:04 ` Jon Brenner
2011-03-24 20:10 ` Jonathan Cameron
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox