sathyanarayanan kuppuswamy schrieb am 08.12.2014 um 20:51: > Hi Jonathan/Hartmut, > > Any other issues with accepting this patch ? Hi, so far, it is already in testing and would sooner or later get into the togreg branch - Jonathan just mentioned lately, that he was very busy on other projects. Concerning the power management part, I am still not convinced that the current solution is 100% safe and clean. Just quoting again, what I mentioned before: "The suspend methods should quiesce the device to stop it from performing I/O." This requirement is not met in the current version. Possible problems I see are I/O errors, as the system might switch into low-power mode while communication to the device is in progress, and an unexpected high power consumption, as the device is powered up while the system has entered a suspend mode. > > On 12/02/2014 02:47 PM, sathyanarayanan kuppuswamy wrote: >> On 12/01/2014 08:58 AM, Srinivas Pandruvada wrote: >>> On Sat, 2014-11-29 at 11:52 +0100, Hartmut Knaack wrote: >>>> Srinivas Pandruvada schrieb am 10.11.2014 um 18:35: >>>>> On Sun, 2014-11-09 at 00:33 +0100, Hartmut Knaack wrote: >>>>>> Srinivas Pandruvada schrieb am 06.11.2014 13:09: >>>>>>> On Thu, 2014-11-06 at 00:26 +0100, Hartmut Knaack wrote: >>>>>>>> Jonathan Cameron schrieb am 05.11.2014 17:11: >>>>>>>>> Hi all, >>>>>>>>> >>>>>>>>> I'm a bit embarrassed. >>>>>>>>> >>>>>>>>> I can't remember at all where we were with this driver! >>>>>>>>> Is everyone happy with it in it's current form or do >>>>>>>>> people feel there are changes outstanding? >>>>>>>>> >>>>>>>>> Jonathan >>>>>>>>> >>>>>>>> Well, I think I lost a bit track by just reading the follow-ups, >>>>>>>> but not putting my focus on everything related. I'm not really >>>>>>>> into power management, so correct me, if I'm wrong. >>>>>>>> My expectation is, that whenever a suspend is triggered, all >>>>>>>> registered .suspend functions are called. The one for this >>>>>>>> driver calls in turn jsa1212_power_off(), which, after doing the >>>>>>>> mutex_lock, puts the device in low power mode. But since >>>>>>>> _read_raw() also locks the same mutex before activating, reading >>>>>>>> and deactivating the device, and then unlocks it again, there >>>>>>>> should not be a need for the suspend function to power down the >>>>>>>> device (and for the resume function to conditionally power it >>>>>>>> back on), as the device should be in low power state anyway. >>>>>>>> That said, shouldn't it be just necessary to put a mutex_lock() >>>>>>>> into _suspend(), and a mutex_unlock() into _resume() to make >>>>>>>> sure that no device access (and thus power up) happens during a >>>>>>>> suspend call? >>>>>>>> >>>>>>> As I explained before, suspend/resume happens in totally on a >>>>>>> different >>>>>>> thread. With autosuspend feature and with config preempt options >>>>>>> even >>>>>>> context switch can happen while processing system call. >>>>>>> So only safe way is to prevent suspend to complete or poweroff in >>>>>>> suspend. >>>>>>> >>>>>>> Thanks, >>>>>>> Srinivas >> I agree with Srinivas comment's. In suspend/resume path, Its safer to >> put the device in the desired state explicitly than expecting it to be >> in the given state. >> >>>>>> I must admit, that I don't feel like understanding your comments >>>>>> completely. That's why I gathered some informations about the >>>>>> phases during suspend (and resume). It is mainly based on a >>>>>> presentation of Rafael J. Wysocki [1] and some documentation in >>>>>> the kernel tree [2]. >>>>>> So, in short, this is what happens during suspend: 1. Call >>>>>> Notifiers -> 2. Freeze Tasks -> 3. Device Suspend (call if >>>>>> defined: .prepare(), .suspend(), .suspend_late(), >>>>>> .suspend_noirq()) -> 4. Nonboot CPU Offline -> 5. System Core >>>>>> Offline -> 6. Turn Off Power. >>>>>> This means, that until step 4, multiple threads can be active. >>>>>> The purpose of .suspend() is defined as: The suspend methods >>>>>> should quiesce the device to stop it from performing I/O. They >>>>>> also may save the device registers and put it into the appropriate >>>>>> low-power state, depending on the bus type the device is on, and >>>>>> they may enable wakeup events. >>>>>> In case of this driver in its current state, _read_raw() can still >>>>>> be called, after .suspend() has been called - which means >>>>>> performing I/O and possibly leaving it in high power state when >>>>>> the system turns off power. >>>>>> So, the most simple solution I could propose (as before) would be >>>>>> to just put the mutex_lock(&data->lock) into .suspend() and the >>>>>> corresponding mutex_unlock(&data->lock) into .resume - thus >>>>>> .suspend() will wait for a potential _read_raw() in progress to >>>>>> finish and power down, as well as preventing _read_raw() from from >>>>>> accessing the device until .resume() has finished. >>>>>> Any comments and pointers to better information welcome. >>>>>> >>>>> Your analysis is correct. My original comment is to whether >>>>> suspend/resume is required when read raw does power on and >>>>> power-off for >>>>> each read. So my comment was why suspend/resume is required as it >>>>> is on >>>>> a parallel thread. But I prefer power-off as someone can do a crazy >>>>> SMI >>>>> handler in turn on ALS (OEMs implement fancy things in SMI), so >>>>> atleast >>>>> next suspend will fix this in low power platforms. We have seen many >>>>> crazy stuff in SMI. But I am not particular about power off. >>>>> >>>>> Thanks, >>>>> Srinivas >>>>> >>>> Any progress on this? Maybe add a suspend flag, which gets set by >>>> .suspend() and cleared by .resume(), so _read_raw() knows when it >>>> should not access the device - basically a mutex? >>>> >>> As I said on x86 there can be a parallel world with SMI handler, so >>> power down is the safest option. So IMO, this driver is doing correctly. >>> ALS is utilized for making power decision, so manufacturers can be >>> creative. >>> >>> Thanks, >>> Srinivas >>> >>>>>> [1]https://events.linuxfoundation.org/sites/events/files/slides/kernel_PM_plain.pdf >>>>>> >>>>>> [2]Documentation/power/devices.txt >>>>>> >>>>>>>> Hartmut >>>>>>>> >>>>>>>>> On 14/10/14 18:38, Jonathan Cameron wrote: >>>>>>>>>> On 14/10/14 17:38, sathyanarayanan kuppuswamy wrote: >>>>>>>>>>> Thanks for your comments Srinivas. >>>>>>>>>>> >>>>>>>>>>> Jonathan, >>>>>>>>>>> >>>>>>>>>>> If you agree with Srinivas comment. I think we don't need to >>>>>>>>>>> remove the suspend >>>>>>>>>>> call backs from the driver. >>>>>>>>>> Yes. >>>>>>>>>>> >>>>>>>>>>> On 10/11/2014 07:57 AM, Srinivas Pandruvada wrote: >>>>>>>>>>>> On Thu, 2014-10-09 at 20:26 +0100, Jonathan Cameron wrote: >>>>>>>>>>>>> On 07/10/14 21:09, sathyanarayanan kuppuswamy wrote: >>>>>>>>>>>>>> Hi Jonathan, >>>>>>>>>>>>>> >>>>>>>>>>>>>> On 09/29/2014 03:00 PM, sathyanarayanan kuppuswamy wrote: >>>>>>>>>>>>>>> Hi Jonathan, >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> On 09/21/2014 05:52 AM, Jonathan Cameron wrote: >>>>>>>>>>>>>>>> On 17/09/14 21:59, sathyanarayanan kuppuswamy wrote: >>>>>>>>>>>>>>>>> Hi Hartmut, >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> On 09/17/2014 01:48 PM, Hartmut Knaack wrote: >>>>>>>>>>>>>>>>>> Kuppuswamy Sathyanarayanan schrieb, Am 16.09.2014 05:54: >>>>>>>>>>>>>>>>>>> This patch adds a new driver for solteam opto JSA1212 >>>>>>>>>>>>>>>>>>> proximity and >>>>>>>>>>>>>>>>>>> ambient light sensor. >>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>> Basic details of the chip can be found here. >>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>> http://www.solteamopto.com.tw/detail.php?ms=3&po_unit=2&pt_unit=29&p_unit=120 >>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>> Hi, >>>>>>>>>>>>>>>>>> after your explanation of the power states, I now >>>>>>>>>>>>>>>>>> wonder, why you would >>>>>>>>>>>>>>>>>> need >>>>>>>>>>>>>>>>>> to power-down the device in jsa1212_suspend() and >>>>>>>>>>>>>>>>>> check, which parts >>>>>>>>>>>>>>>>>> need to >>>>>>>>>>>>>>>>>> be powered-up in jsa1212_resume(). The way I >>>>>>>>>>>>>>>>>> understand it, you only access >>>>>>>>>>>>>>>>>> the device to read data, after initialization. >>>>>>>>>>>>>>>>>> Therefor you power up the >>>>>>>>>>>>>>>>>> device, wait, read data and power down. All secured by >>>>>>>>>>>>>>>>>> a mutex. So, as >>>>>>>>>>>>>>>>>> long as >>>>>>>>>>>>>>>>>> no data is read, the device will always remain in >>>>>>>>>>>>>>>>>> low-power state. >>>>>>>>>>>>>>>>> Yes, What you mentioned is true for current use case. >>>>>>>>>>>>>>>>> But once we implement >>>>>>>>>>>>>>>>> interrupt & IIO event support, We will have scenarios >>>>>>>>>>>>>>>>> where the device is on >>>>>>>>>>>>>>>>> when suspend is triggered. I have just added the power >>>>>>>>>>>>>>>>> management code with >>>>>>>>>>>>>>>>> that >>>>>>>>>>>>>>>>> scenario in mind. >>>>>>>>>>>>>>>> Please drop this for now and reintroduce it as and when >>>>>>>>>>>>>>>> it becomes relevant. >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> If this had been part of a series that added support >>>>>>>>>>>>>>>> needing it in a later >>>>>>>>>>>>>>>> patch then it probably wouldn't have mattered (although >>>>>>>>>>>>>>>> it would still have >>>>>>>>>>>>>>>> been more correct in the patch that needed it). Right >>>>>>>>>>>>>>>> now it adds complexity >>>>>>>>>>>>>>>> for no obvious gain. >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> Also, once you have interrupt support etc you'll >>>>>>>>>>>>>>>> probably need to make >>>>>>>>>>>>>>>> changes >>>>>>>>>>>>>>>> to the current locations where you power up and down the >>>>>>>>>>>>>>>> chip anyway so it >>>>>>>>>>>>>>>> will >>>>>>>>>>>>>>>> fit in well then. >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> Otherwise, a nice little driver. >>>>>>>>>>>>>>> When I answered Hartmut, I missed to consider the >>>>>>>>>>>>>>> scenario where suspend to >>>>>>>>>>>>>>> ram gets triggered in the middle >>>>>>>>>>>>>>> of the read_raw() function. When it happens our device >>>>>>>>>>>>>>> might be "on" and >>>>>>>>>>>>>>> system might be trying to suspend. >>>>>>>>>>>>>>> So I think we still need the suspend/resume call to cover >>>>>>>>>>>>>>> these cases. >>>>>>>>>>>>>> Do you agree with above comment ? If yes, I think there is >>>>>>>>>>>>>> no need to change >>>>>>>>>>>>>> this driver any more. Let me know. >>>>>>>>>>>>> Sorry, misread that as you'd identified an issue (which I >>>>>>>>>>>>> hadn't noticed!) >>>>>>>>>>>>> and were going to fix and repost. >>>>>>>>>>>>> >>>>>>>>>>>>> Hmm. I'm not sure what the semantics of a suspend are. I'd >>>>>>>>>>>>> like to think it >>>>>>>>>>>>> would >>>>>>>>>>>>> require no other function calls to be in flight, but not >>>>>>>>>>>>> certain. >>>>>>>>>>>>> >>>>>>>>>>>>> Anyone else happen to know? >>>>>>>>>>>>> >>>>>>>>>>>> Suspend can happen asynchronously, so if it can happen >>>>>>>>>>>> before read raw >>>>>>>>>>>> can complete. There are OSs where suspend is automatically >>>>>>>>>>>> triggered, if >>>>>>>>>>>> no one blocks it using special locks, without even user process >>>>>>>>>>>> triggering suspend. Some users also define >>>>>>>>>>>> CONFIG_PREEMPT_VOLUNTARY. >>>>>>>>>>>> So Sathya do need to make sure that it power down in suspend >>>>>>>>>>>> callback or >>>>>>>>>>>> atleast prevent suspend to finish before read raw finishes >>>>>>>>>>>> the power >>>>>>>>>>>> down by using some mutexes. >>>>>>>>>>>> >>>>>>>>>>>> Thanks, >>>>>>>>>>>> Srinivas >>>>>>>>>>>> >>>>>>>>>>>>>>>> Thanks, >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> Jonathan >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>> Signed-off-by: Kuppuswamy Sathyanarayanan >>>>>>>>>>>>>>>>>>> <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx> >>>>>>>>>>>>>>>>>>> Signed-off-by: Srinivas Pandruvada >>>>>>>>>>>>>>>>>>> <srinivas.pandruvada@xxxxxxxxxxxxxxx> >>>>>>>>>>>>>>>>>>> --- >>>>>>>>>>>>>>>>>>> drivers/iio/light/Kconfig | 10 + >>>>>>>>>>>>>>>>>>> drivers/iio/light/Makefile | 1 + >>>>>>>>>>>>>>>>>>> drivers/iio/light/jsa1212.c | 471 >>>>>>>>>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++ >>>>>>>>>>>>>>>>>>> 3 files changed, 482 insertions(+) >>>>>>>>>>>>>>>>>>> create mode 100644 drivers/iio/light/jsa1212.c >>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>> diff --git a/drivers/iio/light/Kconfig >>>>>>>>>>>>>>>>>>> b/drivers/iio/light/Kconfig >>>>>>>>>>>>>>>>>>> index bf05ca5..b81d8a3 100644 >>>>>>>>>>>>>>>>>>> --- a/drivers/iio/light/Kconfig >>>>>>>>>>>>>>>>>>> +++ b/drivers/iio/light/Kconfig >>>>>>>>>>>>>>>>>>> @@ -99,6 +99,16 @@ config HID_SENSOR_PROX >>>>>>>>>>>>>>>>>>> To compile this driver as a module, choose >>>>>>>>>>>>>>>>>>> M here: the >>>>>>>>>>>>>>>>>>> module will be called hid-sensor-prox. >>>>>>>>>>>>>>>>>>> +config JSA1212 >>>>>>>>>>>>>>>>>>> + tristate "JSA1212 ALS and proximity sensor driver" >>>>>>>>>>>>>>>>>>> + depends on I2C >>>>>>>>>>>>>>>>>>> + help >>>>>>>>>>>>>>>>>>> + Say Y here if you want to build a IIO driver >>>>>>>>>>>>>>>>>>> for JSA1212 >>>>>>>>>>>>>>>>>>> + proximity & ALS sensor device. >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + To compile this driver as a module, choose M here: >>>>>>>>>>>>>>>>>>> + the module will be called jsa1212. >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> config SENSORS_LM3533 >>>>>>>>>>>>>>>>>>> tristate "LM3533 ambient light sensor" >>>>>>>>>>>>>>>>>>> depends on MFD_LM3533 >>>>>>>>>>>>>>>>>>> diff --git a/drivers/iio/light/Makefile >>>>>>>>>>>>>>>>>>> b/drivers/iio/light/Makefile >>>>>>>>>>>>>>>>>>> index 8b8c09f..23c6aa9 100644 >>>>>>>>>>>>>>>>>>> --- a/drivers/iio/light/Makefile >>>>>>>>>>>>>>>>>>> +++ b/drivers/iio/light/Makefile >>>>>>>>>>>>>>>>>>> @@ -11,6 +11,7 @@ obj-$(CONFIG_GP2AP020A00F) += >>>>>>>>>>>>>>>>>>> gp2ap020a00f.o >>>>>>>>>>>>>>>>>>> obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o >>>>>>>>>>>>>>>>>>> obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o >>>>>>>>>>>>>>>>>>> obj-$(CONFIG_ISL29125) += isl29125.o >>>>>>>>>>>>>>>>>>> +obj-$(CONFIG_JSA1212) += jsa1212.o >>>>>>>>>>>>>>>>>>> obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o >>>>>>>>>>>>>>>>>>> obj-$(CONFIG_LTR501) += ltr501.o >>>>>>>>>>>>>>>>>>> obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o >>>>>>>>>>>>>>>>>>> diff --git a/drivers/iio/light/jsa1212.c >>>>>>>>>>>>>>>>>>> b/drivers/iio/light/jsa1212.c >>>>>>>>>>>>>>>>>>> new file mode 100644 >>>>>>>>>>>>>>>>>>> index 0000000..29de7e7 >>>>>>>>>>>>>>>>>>> --- /dev/null >>>>>>>>>>>>>>>>>>> +++ b/drivers/iio/light/jsa1212.c >>>>>>>>>>>>>>>>>>> @@ -0,0 +1,471 @@ >>>>>>>>>>>>>>>>>>> +/* >>>>>>>>>>>>>>>>>>> + * JSA1212 Ambient Light & Proximity Sensor Driver >>>>>>>>>>>>>>>>>>> + * >>>>>>>>>>>>>>>>>>> + * Copyright (c) 2014, Intel Corporation. >>>>>>>>>>>>>>>>>>> + * >>>>>>>>>>>>>>>>>>> + * This program is free software; you can >>>>>>>>>>>>>>>>>>> redistribute it and/or >>>>>>>>>>>>>>>>>>> modify it >>>>>>>>>>>>>>>>>>> + * under the terms and conditions of the GNU General >>>>>>>>>>>>>>>>>>> Public License, >>>>>>>>>>>>>>>>>>> + * version 2, as published by the Free Software >>>>>>>>>>>>>>>>>>> Foundation. >>>>>>>>>>>>>>>>>>> + * >>>>>>>>>>>>>>>>>>> + * This program is distributed in the hope 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. >>>>>>>>>>>>>>>>>>> + * >>>>>>>>>>>>>>>>>>> + * JSA1212 I2C slave address: 0x44(ADDR tied to >>>>>>>>>>>>>>>>>>> GND), 0x45(ADDR tied >>>>>>>>>>>>>>>>>>> to VDD) >>>>>>>>>>>>>>>>>>> + * >>>>>>>>>>>>>>>>>>> + * TODO: Interrupt support, thresholds, range support. >>>>>>>>>>>>>>>>>>> + */ >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +#include <linux/kernel.h> >>>>>>>>>>>>>>>>>>> +#include <linux/slab.h> >>>>>>>>>>>>>>>>>>> +#include <linux/module.h> >>>>>>>>>>>>>>>>>>> +#include <linux/delay.h> >>>>>>>>>>>>>>>>>>> +#include <linux/i2c.h> >>>>>>>>>>>>>>>>>>> +#include <linux/mutex.h> >>>>>>>>>>>>>>>>>>> +#include <linux/acpi.h> >>>>>>>>>>>>>>>>>>> +#include <linux/regmap.h> >>>>>>>>>>>>>>>>>>> +#include <linux/iio/iio.h> >>>>>>>>>>>>>>>>>>> +#include <linux/iio/sysfs.h> >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +/* JSA1212 reg address */ >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_REG 0x01 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_REG 0x02 >>>>>>>>>>>>>>>>>>> +#define JSA1212_PXS_LT_REG 0x03 >>>>>>>>>>>>>>>>>>> +#define JSA1212_PXS_HT_REG 0x04 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_TH1_REG 0x05 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_TH2_REG 0x06 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_TH3_REG 0x07 >>>>>>>>>>>>>>>>>>> +#define JSA1212_PXS_DATA_REG 0x08 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_DT1_REG 0x09 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_DT2_REG 0x0A >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_RNG_REG 0x0B >>>>>>>>>>>>>>>>>>> +#define JSA1212_MAX_REG 0x0C >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +/* JSA1212 reg masks */ >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_MASK 0xFF >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_MASK 0xFF >>>>>>>>>>>>>>>>>>> +#define JSA1212_PXS_LT_MASK 0xFF >>>>>>>>>>>>>>>>>>> +#define JSA1212_PXS_HT_MASK 0xFF >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_TH1_MASK 0xFF >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_TH2_LT_MASK 0x0F >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_TH2_HT_MASK 0xF0 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_TH3_MASK 0xFF >>>>>>>>>>>>>>>>>>> +#define JSA1212_PXS_DATA_MASK 0xFF >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_DATA_MASK 0x0FFF >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_DT1_MASK 0xFF >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_DT2_MASK 0x0F >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_RNG_MASK 0x07 >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +/* JSA1212 CONF REG bits */ >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_MASK 0x80 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_ENABLE 0x80 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_DISABLE 0x00 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_ALS_MASK 0x04 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_ALS_ENABLE 0x04 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_ALS_DISABLE 0x00 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_IRDR_MASK 0x08 >>>>>>>>>>>>>>>>>>> +/* Proxmity sensing IRDR current sink settings */ >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_IRDR_200MA 0x08 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_IRDR_100MA 0x00 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_SLP_MASK 0x70 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_SLP_0MS 0x70 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_SLP_12MS 0x60 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_SLP_50MS 0x50 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_SLP_75MS 0x40 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_SLP_100MS 0x30 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_SLP_200MS 0x20 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_SLP_400MS 0x10 >>>>>>>>>>>>>>>>>>> +#define JSA1212_CONF_PXS_SLP_800MS 0x00 >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +/* JSA1212 INT REG bits */ >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_CTRL_MASK 0x01 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_CTRL_EITHER 0x00 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_CTRL_BOTH 0x01 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_ALS_PRST_MASK 0x06 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_ALS_PRST_1CONV 0x00 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_ALS_PRST_4CONV 0x02 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_ALS_PRST_8CONV 0x04 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_ALS_PRST_16CONV 0x06 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_ALS_FLAG_MASK 0x08 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_ALS_FLAG_CLR 0x00 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_PXS_PRST_MASK 0x60 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_PXS_PRST_1CONV 0x00 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_PXS_PRST_4CONV 0x20 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_PXS_PRST_8CONV 0x40 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_PXS_PRST_16CONV 0x60 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_PXS_FLAG_MASK 0x80 >>>>>>>>>>>>>>>>>>> +#define JSA1212_INT_PXS_FLAG_CLR 0x00 >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +/* JSA1212 ALS RNG REG bits */ >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_RNG_0_2048 0x00 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_RNG_0_1024 0x01 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_RNG_0_512 0x02 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_RNG_0_256 0x03 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_RNG_0_128 0x04 >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +/* JSA1212 INT threshold range */ >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_TH_MIN 0x0000 >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_TH_MAX 0x0FFF >>>>>>>>>>>>>>>>>>> +#define JSA1212_PXS_TH_MIN 0x00 >>>>>>>>>>>>>>>>>>> +#define JSA1212_PXS_TH_MAX 0xFF >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +#define JSA1212_ALS_DELAY_MS 200 >>>>>>>>>>>>>>>>>>> +#define JSA1212_PXS_DELAY_MS 100 >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +#define JSA1212_DRIVER_NAME "jsa1212" >>>>>>>>>>>>>>>>>>> +#define JSA1212_REGMAP_NAME "jsa1212_regmap" >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +enum jsa1212_op_mode { >>>>>>>>>>>>>>>>>>> + JSA1212_OPMODE_ALS_EN, >>>>>>>>>>>>>>>>>>> + JSA1212_OPMODE_PXS_EN, >>>>>>>>>>>>>>>>>>> +}; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +struct jsa1212_data { >>>>>>>>>>>>>>>>>>> + struct i2c_client *client; >>>>>>>>>>>>>>>>>>> + struct mutex lock; >>>>>>>>>>>>>>>>>>> + u8 als_rng_idx; >>>>>>>>>>>>>>>>>>> + bool als_en; /* ALS enable status */ >>>>>>>>>>>>>>>>>>> + bool pxs_en; /* proximity enable status */ >>>>>>>>>>>>>>>>>>> + struct regmap *regmap; >>>>>>>>>>>>>>>>>>> +}; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +/* ALS range idx to val mapping */ >>>>>>>>>>>>>>>>>>> +static const int jsa1212_als_range_val[] = {2048, >>>>>>>>>>>>>>>>>>> 1024, 512, 256, 128, >>>>>>>>>>>>>>>>>>> + 128, 128, 128}; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +/* Enables or disables ALS function based on status */ >>>>>>>>>>>>>>>>>>> +static int jsa1212_als_enable(struct jsa1212_data >>>>>>>>>>>>>>>>>>> *data, u8 status) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + int ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + ret = regmap_update_bits(data->regmap, >>>>>>>>>>>>>>>>>>> JSA1212_CONF_REG, >>>>>>>>>>>>>>>>>>> + JSA1212_CONF_ALS_MASK, >>>>>>>>>>>>>>>>>>> + status); >>>>>>>>>>>>>>>>>>> + if (ret < 0) >>>>>>>>>>>>>>>>>>> + return ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + data->als_en = !!status; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + return 0; >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +/* Enables or disables PXS function based on status */ >>>>>>>>>>>>>>>>>>> +static int jsa1212_pxs_enable(struct jsa1212_data >>>>>>>>>>>>>>>>>>> *data, u8 status) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + int ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + ret = regmap_update_bits(data->regmap, >>>>>>>>>>>>>>>>>>> JSA1212_CONF_REG, >>>>>>>>>>>>>>>>>>> + JSA1212_CONF_PXS_MASK, >>>>>>>>>>>>>>>>>>> + status); >>>>>>>>>>>>>>>>>>> + if (ret < 0) >>>>>>>>>>>>>>>>>>> + return ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + data->pxs_en = !!status; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + return 0; >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static int jsa1212_read_als_data(struct jsa1212_data >>>>>>>>>>>>>>>>>>> *data, >>>>>>>>>>>>>>>>>>> + unsigned int *val) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + int ret; >>>>>>>>>>>>>>>>>>> + __le16 als_data; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + ret = jsa1212_als_enable(data, >>>>>>>>>>>>>>>>>>> JSA1212_CONF_ALS_ENABLE); >>>>>>>>>>>>>>>>>>> + if (ret < 0) >>>>>>>>>>>>>>>>>>> + return ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + /* Delay for data output */ >>>>>>>>>>>>>>>>>>> + msleep(JSA1212_ALS_DELAY_MS); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + /* Read 12 bit data */ >>>>>>>>>>>>>>>>>>> + ret = regmap_bulk_read(data->regmap, >>>>>>>>>>>>>>>>>>> JSA1212_ALS_DT1_REG, >>>>>>>>>>>>>>>>>>> &als_data, 2); >>>>>>>>>>>>>>>>>>> + if (ret < 0) { >>>>>>>>>>>>>>>>>>> + dev_err(&data->client->dev, "als data read err\n"); >>>>>>>>>>>>>>>>>>> + goto als_data_read_err; >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + *val = le16_to_cpu(als_data); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +als_data_read_err: >>>>>>>>>>>>>>>>>>> + return jsa1212_als_enable(data, >>>>>>>>>>>>>>>>>>> JSA1212_CONF_ALS_DISABLE); >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static int jsa1212_read_pxs_data(struct jsa1212_data >>>>>>>>>>>>>>>>>>> *data, >>>>>>>>>>>>>>>>>>> + unsigned int *val) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + int ret; >>>>>>>>>>>>>>>>>>> + unsigned int pxs_data; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + ret = jsa1212_pxs_enable(data, >>>>>>>>>>>>>>>>>>> JSA1212_CONF_PXS_ENABLE); >>>>>>>>>>>>>>>>>>> + if (ret < 0) >>>>>>>>>>>>>>>>>>> + return ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + /* Delay for data output */ >>>>>>>>>>>>>>>>>>> + msleep(JSA1212_PXS_DELAY_MS); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + /* Read out all data */ >>>>>>>>>>>>>>>>>>> + ret = regmap_read(data->regmap, >>>>>>>>>>>>>>>>>>> JSA1212_PXS_DATA_REG, &pxs_data); >>>>>>>>>>>>>>>>>>> + if (ret < 0) { >>>>>>>>>>>>>>>>>>> + dev_err(&data->client->dev, "pxs data read err\n"); >>>>>>>>>>>>>>>>>>> + goto pxs_data_read_err; >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + *val = pxs_data & JSA1212_PXS_DATA_MASK; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +pxs_data_read_err: >>>>>>>>>>>>>>>>>>> + return jsa1212_pxs_enable(data, >>>>>>>>>>>>>>>>>>> JSA1212_CONF_PXS_DISABLE); >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static int jsa1212_read_raw(struct iio_dev *indio_dev, >>>>>>>>>>>>>>>>>>> + struct iio_chan_spec const *chan, >>>>>>>>>>>>>>>>>>> + int *val, int *val2, long mask) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + int ret; >>>>>>>>>>>>>>>>>>> + struct jsa1212_data *data = iio_priv(indio_dev); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + switch (mask) { >>>>>>>>>>>>>>>>>>> + case IIO_CHAN_INFO_RAW: >>>>>>>>>>>>>>>>>>> + mutex_lock(&data->lock); >>>>>>>>>>>>>>>>>>> + switch (chan->type) { >>>>>>>>>>>>>>>>>>> + case IIO_LIGHT: >>>>>>>>>>>>>>>>>>> + ret = jsa1212_read_als_data(data, val); >>>>>>>>>>>>>>>>>>> + break; >>>>>>>>>>>>>>>>>>> + case IIO_PROXIMITY: >>>>>>>>>>>>>>>>>>> + ret = jsa1212_read_pxs_data(data, val); >>>>>>>>>>>>>>>>>>> + break; >>>>>>>>>>>>>>>>>>> + default: >>>>>>>>>>>>>>>>>>> + ret = -EINVAL; >>>>>>>>>>>>>>>>>>> + break; >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> + mutex_unlock(&data->lock); >>>>>>>>>>>>>>>>>>> + return ret < 0 ? ret : IIO_VAL_INT; >>>>>>>>>>>>>>>>>>> + case IIO_CHAN_INFO_SCALE: >>>>>>>>>>>>>>>>>>> + switch (chan->type) { >>>>>>>>>>>>>>>>>>> + case IIO_LIGHT: >>>>>>>>>>>>>>>>>>> + *val = >>>>>>>>>>>>>>>>>>> jsa1212_als_range_val[data->als_rng_idx]; >>>>>>>>>>>>>>>>>>> + *val2 = BIT(12); /* Max 12 bit value */ >>>>>>>>>>>>>>>>>>> + return IIO_VAL_FRACTIONAL; >>>>>>>>>>>>>>>>>>> + default: >>>>>>>>>>>>>>>>>>> + break; >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> + break; >>>>>>>>>>>>>>>>>>> + default: >>>>>>>>>>>>>>>>>>> + break; >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + return -EINVAL; >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static const struct iio_chan_spec jsa1212_channels[] >>>>>>>>>>>>>>>>>>> = { >>>>>>>>>>>>>>>>>>> + { >>>>>>>>>>>>>>>>>>> + .type = IIO_LIGHT, >>>>>>>>>>>>>>>>>>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | >>>>>>>>>>>>>>>>>>> + BIT(IIO_CHAN_INFO_SCALE), >>>>>>>>>>>>>>>>>>> + }, >>>>>>>>>>>>>>>>>>> + { >>>>>>>>>>>>>>>>>>> + .type = IIO_PROXIMITY, >>>>>>>>>>>>>>>>>>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> +}; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static const struct iio_info jsa1212_info = { >>>>>>>>>>>>>>>>>>> + .driver_module = THIS_MODULE, >>>>>>>>>>>>>>>>>>> + .read_raw = &jsa1212_read_raw, >>>>>>>>>>>>>>>>>>> +}; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static int jsa1212_chip_init(struct jsa1212_data *data) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + int ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + ret = regmap_write(data->regmap, JSA1212_CONF_REG, >>>>>>>>>>>>>>>>>>> + (JSA1212_CONF_PXS_SLP_50MS | >>>>>>>>>>>>>>>>>>> + JSA1212_CONF_IRDR_200MA)); >>>>>>>>>>>>>>>>>>> + if (ret < 0) >>>>>>>>>>>>>>>>>>> + return ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + ret = regmap_write(data->regmap, JSA1212_INT_REG, >>>>>>>>>>>>>>>>>>> + JSA1212_INT_ALS_PRST_4CONV); >>>>>>>>>>>>>>>>>>> + if (ret < 0) >>>>>>>>>>>>>>>>>>> + return ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + data->als_rng_idx = JSA1212_ALS_RNG_0_2048; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + return 0; >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static bool jsa1212_is_volatile_reg(struct device >>>>>>>>>>>>>>>>>>> *dev, unsigned int reg) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + switch (reg) { >>>>>>>>>>>>>>>>>>> + case JSA1212_PXS_DATA_REG: >>>>>>>>>>>>>>>>>>> + case JSA1212_ALS_DT1_REG: >>>>>>>>>>>>>>>>>>> + case JSA1212_ALS_DT2_REG: >>>>>>>>>>>>>>>>>>> + case JSA1212_INT_REG: >>>>>>>>>>>>>>>>>>> + return true; >>>>>>>>>>>>>>>>>>> + default: >>>>>>>>>>>>>>>>>>> + return false; >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static struct regmap_config jsa1212_regmap_config = { >>>>>>>>>>>>>>>>>>> + .name = JSA1212_REGMAP_NAME, >>>>>>>>>>>>>>>>>>> + .reg_bits = 8, >>>>>>>>>>>>>>>>>>> + .val_bits = 8, >>>>>>>>>>>>>>>>>>> + .max_register = JSA1212_MAX_REG, >>>>>>>>>>>>>>>>>>> + .cache_type = REGCACHE_RBTREE, >>>>>>>>>>>>>>>>>>> + .volatile_reg = jsa1212_is_volatile_reg, >>>>>>>>>>>>>>>>>>> +}; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static int jsa1212_probe(struct i2c_client *client, >>>>>>>>>>>>>>>>>>> + const struct i2c_device_id *id) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + struct jsa1212_data *data; >>>>>>>>>>>>>>>>>>> + struct iio_dev *indio_dev; >>>>>>>>>>>>>>>>>>> + struct regmap *regmap; >>>>>>>>>>>>>>>>>>> + int ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + if (!i2c_check_functionality(client->adapter, >>>>>>>>>>>>>>>>>>> I2C_FUNC_SMBUS_BYTE_DATA)) >>>>>>>>>>>>>>>>>>> + return -ENODEV; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + indio_dev = devm_iio_device_alloc(&client->dev, >>>>>>>>>>>>>>>>>>> sizeof(*data)); >>>>>>>>>>>>>>>>>>> + if (!indio_dev) >>>>>>>>>>>>>>>>>>> + return -ENOMEM; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + regmap = devm_regmap_init_i2c(client, >>>>>>>>>>>>>>>>>>> &jsa1212_regmap_config); >>>>>>>>>>>>>>>>>>> + if (IS_ERR(regmap)) { >>>>>>>>>>>>>>>>>>> + dev_err(&client->dev, "Regmap initialization >>>>>>>>>>>>>>>>>>> failed.\n"); >>>>>>>>>>>>>>>>>>> + return PTR_ERR(regmap); >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + data = iio_priv(indio_dev); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + i2c_set_clientdata(client, indio_dev); >>>>>>>>>>>>>>>>>>> + data->client = client; >>>>>>>>>>>>>>>>>>> + data->regmap = regmap; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + mutex_init(&data->lock); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + ret = jsa1212_chip_init(data); >>>>>>>>>>>>>>>>>>> + if (ret < 0) >>>>>>>>>>>>>>>>>>> + return ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + indio_dev->dev.parent = &client->dev; >>>>>>>>>>>>>>>>>>> + indio_dev->channels = jsa1212_channels; >>>>>>>>>>>>>>>>>>> + indio_dev->num_channels = >>>>>>>>>>>>>>>>>>> ARRAY_SIZE(jsa1212_channels); >>>>>>>>>>>>>>>>>>> + indio_dev->name = JSA1212_DRIVER_NAME; >>>>>>>>>>>>>>>>>>> + indio_dev->modes = INDIO_DIRECT_MODE; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + indio_dev->info = &jsa1212_info; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + ret = iio_device_register(indio_dev); >>>>>>>>>>>>>>>>>>> + if (ret < 0) >>>>>>>>>>>>>>>>>>> + dev_err(&client->dev, "%s: register device >>>>>>>>>>>>>>>>>>> failed\n", __func__); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + return ret; >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + /* power off the device */ >>>>>>>>>>>>>>>>>>> +static int jsa1212_power_off(struct jsa1212_data *data) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + int ret; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + mutex_lock(&data->lock); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + ret = regmap_update_bits(data->regmap, >>>>>>>>>>>>>>>>>>> JSA1212_CONF_REG, >>>>>>>>>>>>>>>>>>> + JSA1212_CONF_ALS_MASK | >>>>>>>>>>>>>>>>>>> + JSA1212_CONF_PXS_MASK, >>>>>>>>>>>>>>>>>>> + JSA1212_CONF_ALS_DISABLE | >>>>>>>>>>>>>>>>>>> + JSA1212_CONF_PXS_DISABLE); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + if (ret < 0) >>>>>>>>>>>>>>>>>>> + dev_err(&data->client->dev, "power off cmd failed\n"); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + mutex_unlock(&data->lock); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + return ret; >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static int jsa1212_remove(struct i2c_client *client) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + struct iio_dev *indio_dev = >>>>>>>>>>>>>>>>>>> i2c_get_clientdata(client); >>>>>>>>>>>>>>>>>>> + struct jsa1212_data *data = iio_priv(indio_dev); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + iio_device_unregister(indio_dev); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + return jsa1212_power_off(data); >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +#ifdef CONFIG_PM_SLEEP >>>>>>>>>>>>>>>>>>> +static int jsa1212_suspend(struct device *dev) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + struct jsa1212_data *data; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + data = >>>>>>>>>>>>>>>>>>> iio_priv(i2c_get_clientdata(to_i2c_client(dev))); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + return jsa1212_power_off(data); >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static int jsa1212_resume(struct device *dev) >>>>>>>>>>>>>>>>>>> +{ >>>>>>>>>>>>>>>>>>> + int ret = 0; >>>>>>>>>>>>>>>>>>> + struct jsa1212_data *data; >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + data = >>>>>>>>>>>>>>>>>>> iio_priv(i2c_get_clientdata(to_i2c_client(dev))); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + mutex_lock(&data->lock); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + if (data->als_en) { >>>>>>>>>>>>>>>>>>> + ret = jsa1212_als_enable(data, >>>>>>>>>>>>>>>>>>> JSA1212_CONF_ALS_ENABLE); >>>>>>>>>>>>>>>>>>> + if (ret < 0) { >>>>>>>>>>>>>>>>>>> + dev_err(dev, "als resume failed\n"); >>>>>>>>>>>>>>>>>>> + goto unlock_and_ret; >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> + if (data->pxs_en) { >>>>>>>>>>>>>>>>>>> + ret = jsa1212_pxs_enable(data, >>>>>>>>>>>>>>>>>>> JSA1212_CONF_PXS_ENABLE); >>>>>>>>>>>>>>>>>>> + if (ret < 0) >>>>>>>>>>>>>>>>>>> + dev_err(dev, "pxs resume failed\n"); >>>>>>>>>>>>>>>>>>> + } >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +unlock_and_ret: >>>>>>>>>>>>>>>>>>> + mutex_unlock(&data->lock); >>>>>>>>>>>>>>>>>>> + return ret; >>>>>>>>>>>>>>>>>>> +} >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static SIMPLE_DEV_PM_OPS(jsa1212_pm_ops, >>>>>>>>>>>>>>>>>>> jsa1212_suspend, >>>>>>>>>>>>>>>>>>> jsa1212_resume); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +#define JSA1212_PM_OPS (&jsa1212_pm_ops) >>>>>>>>>>>>>>>>>>> +#else >>>>>>>>>>>>>>>>>>> +#define JSA1212_PM_OPS NULL >>>>>>>>>>>>>>>>>>> +#endif >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static const struct acpi_device_id >>>>>>>>>>>>>>>>>>> jsa1212_acpi_match[] = { >>>>>>>>>>>>>>>>>>> + {"JSA1212", 0}, >>>>>>>>>>>>>>>>>>> + { }, >>>>>>>>>>>>>>>>>>> +}; >>>>>>>>>>>>>>>>>>> +MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static const struct i2c_device_id jsa1212_id[] = { >>>>>>>>>>>>>>>>>>> + { JSA1212_DRIVER_NAME, 0 }, >>>>>>>>>>>>>>>>>>> + { } >>>>>>>>>>>>>>>>>>> +}; >>>>>>>>>>>>>>>>>>> +MODULE_DEVICE_TABLE(i2c, jsa1212_id); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +static struct i2c_driver jsa1212_driver = { >>>>>>>>>>>>>>>>>>> + .driver = { >>>>>>>>>>>>>>>>>>> + .name = JSA1212_DRIVER_NAME, >>>>>>>>>>>>>>>>>>> + .pm = JSA1212_PM_OPS, >>>>>>>>>>>>>>>>>>> + .owner = THIS_MODULE, >>>>>>>>>>>>>>>>>>> + .acpi_match_table = >>>>>>>>>>>>>>>>>>> ACPI_PTR(jsa1212_acpi_match), >>>>>>>>>>>>>>>>>>> + }, >>>>>>>>>>>>>>>>>>> + .probe = jsa1212_probe, >>>>>>>>>>>>>>>>>>> + .remove = jsa1212_remove, >>>>>>>>>>>>>>>>>>> + .id_table = jsa1212_id, >>>>>>>>>>>>>>>>>>> +}; >>>>>>>>>>>>>>>>>>> +module_i2c_driver(jsa1212_driver); >>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>> +MODULE_AUTHOR("Sathya Kuppuswamy >>>>>>>>>>>>>>>>>>> <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx>"); >>>>>>>>>>>>>>>>>>> +MODULE_DESCRIPTION("JSA1212 proximity/ambient light >>>>>>>>>>>>>>>>>>> sensor driver"); >>>>>>>>>>>>>>>>>>> +MODULE_LICENSE("GPL v2"); >>>>>>>>>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>> -- >>>>>>>>>> To unsubscribe from this list: send the line "unsubscribe >>>>>>>>>> linux-iio" in >>>>>>>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx >>>>>>>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>>>>>>>> >>>>>>>>> -- >>>>>>>>> To unsubscribe from this list: send the line "unsubscribe >>>>>>>>> linux-iio" in >>>>>>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx >>>>>>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>>>>>>> >>>>>>> >>>>>>> -- >>>>>>> To unsubscribe from this list: send the line "unsubscribe >>>>>>> linux-iio" in >>>>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx >>>>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>>>>> >>>>> >>>>> -- >>>>> To unsubscribe from this list: send the line "unsubscribe >>>>> linux-iio" in >>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx >>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>>> >>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in >>> the body of a message to majordomo@xxxxxxxxxxxxxxx >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>> >> > -- To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html