Re: [PATCH v7 1/1] iio: jsa1212: Add JSA1212 proximity/ALS sensor

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux