From 5a0b8cb46624cc17fda676d6ae44fb72504f0ad9 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Tue, 13 Mar 2018 14:23:28 -0700 Subject: iio: cros_ec: Move cros_ec_sensors_core.h in /include Similar to other common iio frameworks, move cros_ec_sensors_core.h from drivers/iio/common/cros_ec_sensors/ to include/linux/iio/common. Signed-off-by: Gwendal Grignou Signed-off-by: Jonathan Cameron --- include/linux/iio/common/cros_ec_sensors_core.h | 180 ++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 include/linux/iio/common/cros_ec_sensors_core.h (limited to 'include') diff --git a/include/linux/iio/common/cros_ec_sensors_core.h b/include/linux/iio/common/cros_ec_sensors_core.h new file mode 100644 index 000000000000..ce16445411ac --- /dev/null +++ b/include/linux/iio/common/cros_ec_sensors_core.h @@ -0,0 +1,180 @@ +/* + * ChromeOS EC sensor hub + * + * Copyright (C) 2016 Google, Inc + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#ifndef __CROS_EC_SENSORS_CORE_H +#define __CROS_EC_SENSORS_CORE_H + +#include +#include +#include + +enum { + CROS_EC_SENSOR_X, + CROS_EC_SENSOR_Y, + CROS_EC_SENSOR_Z, + CROS_EC_SENSOR_MAX_AXIS, +}; + +/* EC returns sensor values using signed 16 bit registers */ +#define CROS_EC_SENSOR_BITS 16 + +/* + * 4 16 bit channels are allowed. + * Good enough for current sensors, they use up to 3 16 bit vectors. + */ +#define CROS_EC_SAMPLE_SIZE (sizeof(s64) * 2) + +/* Minimum sampling period to use when device is suspending */ +#define CROS_EC_MIN_SUSPEND_SAMPLING_FREQUENCY 1000 /* 1 second */ + +/** + * struct cros_ec_sensors_core_state - state data for EC sensors IIO driver + * @ec: cros EC device structure + * @cmd_lock: lock used to prevent simultaneous access to the + * commands. + * @msg: cros EC command structure + * @param: motion sensor parameters structure + * @resp: motion sensor response structure + * @type: type of motion sensor + * @loc: location where the motion sensor is placed + * @calib: calibration parameters. Note that trigger + * captured data will always provide the calibrated + * data + * @samples: static array to hold data from a single capture. + * For each channel we need 2 bytes, except for + * the timestamp. The timestamp is always last and + * is always 8-byte aligned. + * @read_ec_sensors_data: function used for accessing sensors values + * @cuur_sampl_freq: current sampling period + */ +struct cros_ec_sensors_core_state { + struct cros_ec_device *ec; + struct mutex cmd_lock; + + struct cros_ec_command *msg; + struct ec_params_motion_sense param; + struct ec_response_motion_sense *resp; + + enum motionsensor_type type; + enum motionsensor_location loc; + + s16 calib[CROS_EC_SENSOR_MAX_AXIS]; + + u8 samples[CROS_EC_SAMPLE_SIZE]; + + int (*read_ec_sensors_data)(struct iio_dev *indio_dev, + unsigned long scan_mask, s16 *data); + + int curr_sampl_freq; +}; + +/** + * cros_ec_sensors_read_lpc() - retrieve data from EC shared memory + * @indio_dev: pointer to IIO device + * @scan_mask: bitmap of the sensor indices to scan + * @data: location to store data + * + * This is the safe function for reading the EC data. It guarantees that the + * data sampled was not modified by the EC while being read. + * + * Return: 0 on success, -errno on failure. + */ +int cros_ec_sensors_read_lpc(struct iio_dev *indio_dev, unsigned long scan_mask, + s16 *data); + +/** + * cros_ec_sensors_read_cmd() - retrieve data using the EC command protocol + * @indio_dev: pointer to IIO device + * @scan_mask: bitmap of the sensor indices to scan + * @data: location to store data + * + * Return: 0 on success, -errno on failure. + */ +int cros_ec_sensors_read_cmd(struct iio_dev *indio_dev, unsigned long scan_mask, + s16 *data); + +struct platform_device; +/** + * cros_ec_sensors_core_init() - basic initialization of the core structure + * @pdev: platform device created for the sensors + * @indio_dev: iio device structure of the device + * @physical_device: true if the device refers to a physical device + * + * Return: 0 on success, -errno on failure. + */ +int cros_ec_sensors_core_init(struct platform_device *pdev, + struct iio_dev *indio_dev, bool physical_device); + +/** + * cros_ec_sensors_capture() - the trigger handler function + * @irq: the interrupt number. + * @p: a pointer to the poll function. + * + * On a trigger event occurring, if the pollfunc is attached then this + * handler is called as a threaded interrupt (and hence may sleep). It + * is responsible for grabbing data from the device and pushing it into + * the associated buffer. + * + * Return: IRQ_HANDLED + */ +irqreturn_t cros_ec_sensors_capture(int irq, void *p); + +/** + * cros_ec_motion_send_host_cmd() - send motion sense host command + * @st: pointer to state information for device + * @opt_length: optional length to reduce the response size, useful on the data + * path. Otherwise, the maximal allowed response size is used + * + * When called, the sub-command is assumed to be set in param->cmd. + * + * Return: 0 on success, -errno on failure. + */ +int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *st, + u16 opt_length); + +/** + * cros_ec_sensors_core_read() - function to request a value from the sensor + * @st: pointer to state information for device + * @chan: channel specification structure table + * @val: will contain one element making up the returned value + * @val2: will contain another element making up the returned value + * @mask: specifies which values to be requested + * + * Return: the type of value returned by the device + */ +int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask); + +/** + * cros_ec_sensors_core_write() - function to write a value to the sensor + * @st: pointer to state information for device + * @chan: channel specification structure table + * @val: first part of value to write + * @val2: second part of value to write + * @mask: specifies which values to write + * + * Return: the type of value returned by the device + */ +int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st, + struct iio_chan_spec const *chan, + int val, int val2, long mask); + +extern const struct dev_pm_ops cros_ec_sensors_pm_ops; + +/* List of extended channel specification for all sensors */ +extern const struct iio_chan_spec_ext_info cros_ec_sensors_ext_info[]; + +#endif /* __CROS_EC_SENSORS_CORE_H */ -- cgit v1.2.3-71-gd317 From 192af06a287bbfcae0de8fa456dca15767ecd056 Mon Sep 17 00:00:00 2001 From: Alexandru Ardelean Date: Mon, 12 Mar 2018 17:48:15 +0200 Subject: iio: adc: ad7780: remove IIO_CHAN_INFO_SAMP_FREQ support The `ad7780` driver does not implement setting/getting the sampling frequency. For the ad7780/ad7781 devices, the control is done via an external pin, and the ad7170/ad7171 devices have a fixed sampling rate (so, no control). For these devices, and similar other that may be added later on, a AD_SD_CHANNEL_NO_SAMPLE_FREQ() macro has been added, which doesn't set the IIO_CHAN_INFO_SAMP_FREQ flag. Signed-off-by: Alexandru Ardelean Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/ad7780.c | 2 +- include/linux/iio/adc/ad_sigma_delta.h | 24 +++++++++++++++++------- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c index a7797af579b9..16d72072c076 100644 --- a/drivers/staging/iio/adc/ad7780.c +++ b/drivers/staging/iio/adc/ad7780.c @@ -128,7 +128,7 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = { }; #define AD7780_CHANNEL(bits, wordsize) \ - AD_SD_CHANNEL(1, 0, 0, bits, 32, wordsize - bits) + AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, wordsize - bits) static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { [ID_AD7170] = { diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h index 1fc7abd28b0b..730ead1a46df 100644 --- a/include/linux/iio/adc/ad_sigma_delta.h +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -127,7 +127,7 @@ void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev); int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig); #define __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ - _storagebits, _shift, _extend_name, _type) \ + _storagebits, _shift, _extend_name, _type, _mask_all) \ { \ .type = (_type), \ .differential = (_channel2 == -1 ? 0 : 1), \ @@ -139,7 +139,7 @@ int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig); .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_OFFSET), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_shared_by_all = _mask_all, \ .scan_index = (_si), \ .scan_type = { \ .sign = 'u', \ @@ -153,25 +153,35 @@ int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig); #define AD_SD_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ _storagebits, _shift) \ __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ - _storagebits, _shift, NULL, IIO_VOLTAGE) + _storagebits, _shift, NULL, IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) #define AD_SD_SHORTED_CHANNEL(_si, _channel, _address, _bits, \ _storagebits, _shift) \ __AD_SD_CHANNEL(_si, _channel, _channel, _address, _bits, \ - _storagebits, _shift, "shorted", IIO_VOLTAGE) + _storagebits, _shift, "shorted", IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) #define AD_SD_CHANNEL(_si, _channel, _address, _bits, \ _storagebits, _shift) \ __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ - _storagebits, _shift, NULL, IIO_VOLTAGE) + _storagebits, _shift, NULL, IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + +#define AD_SD_CHANNEL_NO_SAMP_FREQ(_si, _channel, _address, _bits, \ + _storagebits, _shift) \ + __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ + _storagebits, _shift, NULL, IIO_VOLTAGE, 0) #define AD_SD_TEMP_CHANNEL(_si, _address, _bits, _storagebits, _shift) \ __AD_SD_CHANNEL(_si, 0, -1, _address, _bits, \ - _storagebits, _shift, NULL, IIO_TEMP) + _storagebits, _shift, NULL, IIO_TEMP, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) #define AD_SD_SUPPLY_CHANNEL(_si, _channel, _address, _bits, _storagebits, \ _shift) \ __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ - _storagebits, _shift, "supply", IIO_VOLTAGE) + _storagebits, _shift, "supply", IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) #endif -- cgit v1.2.3-71-gd317 From 05e6557b8ed833546ee2b66ce6b58fecf09f439e Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 29 Mar 2018 15:26:48 +1100 Subject: staging: lustre: add container_of_safe() Luster has a container_of0() function which is similar to container_of() but passes an IS_ERR_OR_NULL() pointer through unchanged. This could be generally useful: bcache at last has a similar function. Naming is hard, but the precedent set by hlist_entry_safe() suggests a _safe suffix might be most consistent. So add container_of_safe() to kernel.h, and replace all occurrences of container_of0() with one of - list_first_entry, list_next_entry, when that is a better fit, - container_of(), when the pointer is used as a validpointer in surrounding code, - container_of_safe() when there is no obviously better alternative. Signed-off-by: NeilBrown Reviewed-by: James Simmons Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/include/linux/libcfs/libcfs.h | 11 ----------- drivers/staging/lustre/lustre/include/cl_object.h | 10 +++++----- drivers/staging/lustre/lustre/include/lu_object.h | 6 +++--- drivers/staging/lustre/lustre/llite/llite_nfs.c | 2 +- drivers/staging/lustre/lustre/llite/vvp_internal.h | 8 ++++---- drivers/staging/lustre/lustre/lmv/lmv_internal.h | 2 +- drivers/staging/lustre/lustre/lov/lov_cl_internal.h | 18 +++++++++--------- drivers/staging/lustre/lustre/lov/lov_internal.h | 2 +- drivers/staging/lustre/lustre/obdclass/lu_object.c | 8 ++++---- drivers/staging/lustre/lustre/obdecho/echo_client.c | 2 +- drivers/staging/lustre/lustre/osc/osc_cl_internal.h | 10 +++++----- drivers/staging/lustre/lustre/osc/osc_internal.h | 2 +- drivers/staging/lustre/lustre/osc/osc_io.c | 2 +- drivers/staging/lustre/lustre/osc/osc_object.c | 2 +- include/linux/kernel.h | 16 ++++++++++++++++ 15 files changed, 53 insertions(+), 48 deletions(-) (limited to 'include') diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h index 5d10aa32895b..6e7754b2f296 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h @@ -143,17 +143,6 @@ int libcfs_ioctl_getdata(struct libcfs_ioctl_hdr **hdr_pp, int libcfs_ioctl_data_adjust(struct libcfs_ioctl_data *data); int libcfs_ioctl(unsigned long cmd, void __user *arg); -/* container_of depends on "likely" which is defined in libcfs_private.h */ -static inline void *__container_of(void *ptr, unsigned long shift) -{ - if (IS_ERR_OR_NULL(ptr)) - return ptr; - return (char *)ptr - shift; -} - -#define container_of0(ptr, type, member) \ - ((type *)__container_of((void *)(ptr), offsetof(type, member))) - #define _LIBCFS_H extern struct miscdevice libcfs_dev; diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h index 341a145c3331..6f7b991be809 100644 --- a/drivers/staging/lustre/lustre/include/cl_object.h +++ b/drivers/staging/lustre/lustre/include/cl_object.h @@ -1941,7 +1941,7 @@ static inline int lu_device_is_cl(const struct lu_device *d) static inline struct cl_device *lu2cl_dev(const struct lu_device *d) { LASSERT(!d || IS_ERR(d) || lu_device_is_cl(d)); - return container_of0(d, struct cl_device, cd_lu_dev); + return container_of_safe(d, struct cl_device, cd_lu_dev); } static inline struct lu_device *cl2lu_dev(struct cl_device *d) @@ -1952,13 +1952,13 @@ static inline struct lu_device *cl2lu_dev(struct cl_device *d) static inline struct cl_object *lu2cl(const struct lu_object *o) { LASSERT(!o || IS_ERR(o) || lu_device_is_cl(o->lo_dev)); - return container_of0(o, struct cl_object, co_lu); + return container_of_safe(o, struct cl_object, co_lu); } static inline const struct cl_object_conf * lu2cl_conf(const struct lu_object_conf *conf) { - return container_of0(conf, struct cl_object_conf, coc_lu); + return container_of_safe(conf, struct cl_object_conf, coc_lu); } static inline struct cl_object *cl_object_next(const struct cl_object *obj) @@ -1969,12 +1969,12 @@ static inline struct cl_object *cl_object_next(const struct cl_object *obj) static inline struct cl_device *cl_object_device(const struct cl_object *o) { LASSERT(!o || IS_ERR(o) || lu_device_is_cl(o->co_lu.lo_dev)); - return container_of0(o->co_lu.lo_dev, struct cl_device, cd_lu_dev); + return container_of_safe(o->co_lu.lo_dev, struct cl_device, cd_lu_dev); } static inline struct cl_object_header *luh2coh(const struct lu_object_header *h) { - return container_of0(h, struct cl_object_header, coh_lu); + return container_of_safe(h, struct cl_object_header, coh_lu); } static inline struct cl_site *cl_object_site(const struct cl_object *obj) diff --git a/drivers/staging/lustre/lustre/include/lu_object.h b/drivers/staging/lustre/lustre/include/lu_object.h index 35c7b582f36d..c3b0ed518819 100644 --- a/drivers/staging/lustre/lustre/include/lu_object.h +++ b/drivers/staging/lustre/lustre/include/lu_object.h @@ -745,15 +745,15 @@ struct lu_object *lu_object_find_slice(const struct lu_env *env, static inline struct lu_object *lu_object_top(struct lu_object_header *h) { LASSERT(!list_empty(&h->loh_layers)); - return container_of0(h->loh_layers.next, struct lu_object, lo_linkage); + return list_first_entry(&h->loh_layers, struct lu_object, lo_linkage); } /** * Next sub-object in the layering */ -static inline struct lu_object *lu_object_next(const struct lu_object *o) +static inline const struct lu_object *lu_object_next(const struct lu_object *o) { - return container_of0(o->lo_linkage.next, struct lu_object, lo_linkage); + return list_next_entry(o, lo_linkage); } /** diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c index a6a1d80c711a..14172688d55f 100644 --- a/drivers/staging/lustre/lustre/llite/llite_nfs.c +++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c @@ -223,7 +223,7 @@ static int ll_nfs_get_name_filldir(struct dir_context *ctx, const char *name, /* It is hack to access lde_fid for comparison with lgd_fid. * So the input 'name' must be part of the 'lu_dirent'. */ - struct lu_dirent *lde = container_of0(name, struct lu_dirent, lde_name); + struct lu_dirent *lde = container_of((void*)name, struct lu_dirent, lde_name); struct ll_getname_data *lgd = container_of(ctx, struct ll_getname_data, ctx); struct lu_fid fid; diff --git a/drivers/staging/lustre/lustre/llite/vvp_internal.h b/drivers/staging/lustre/lustre/llite/vvp_internal.h index 02ea5161d635..7d3abb43584a 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_internal.h +++ b/drivers/staging/lustre/lustre/llite/vvp_internal.h @@ -263,22 +263,22 @@ static inline struct lu_device *vvp2lu_dev(struct vvp_device *vdv) static inline struct vvp_device *lu2vvp_dev(const struct lu_device *d) { - return container_of0(d, struct vvp_device, vdv_cl.cd_lu_dev); + return container_of_safe(d, struct vvp_device, vdv_cl.cd_lu_dev); } static inline struct vvp_device *cl2vvp_dev(const struct cl_device *d) { - return container_of0(d, struct vvp_device, vdv_cl); + return container_of_safe(d, struct vvp_device, vdv_cl); } static inline struct vvp_object *cl2vvp(const struct cl_object *obj) { - return container_of0(obj, struct vvp_object, vob_cl); + return container_of_safe(obj, struct vvp_object, vob_cl); } static inline struct vvp_object *lu2vvp(const struct lu_object *obj) { - return container_of0(obj, struct vvp_object, vob_cl.co_lu); + return container_of_safe(obj, struct vvp_object, vob_cl.co_lu); } static inline struct inode *vvp_object_inode(const struct cl_object *obj) diff --git a/drivers/staging/lustre/lustre/lmv/lmv_internal.h b/drivers/staging/lustre/lustre/lmv/lmv_internal.h index c27c3c32188d..68a99170c424 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_internal.h +++ b/drivers/staging/lustre/lustre/lmv/lmv_internal.h @@ -60,7 +60,7 @@ int lmv_revalidate_slaves(struct obd_export *exp, static inline struct obd_device *lmv2obd_dev(struct lmv_obd *lmv) { - return container_of0(lmv, struct obd_device, u.lmv); + return container_of_safe(lmv, struct obd_device, u.lmv); } static inline struct lmv_tgt_desc * diff --git a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h index 1185eceaf497..2e9c75ebdda5 100644 --- a/drivers/staging/lustre/lustre/lov/lov_cl_internal.h +++ b/drivers/staging/lustre/lustre/lov/lov_cl_internal.h @@ -496,7 +496,7 @@ static inline struct lu_device *lov2lu_dev(struct lov_device *lov) static inline struct lov_device *lu2lov_dev(const struct lu_device *d) { LINVRNT(d->ld_type == &lov_device_type); - return container_of0(d, struct lov_device, ld_cl.cd_lu_dev); + return container_of(d, struct lov_device, ld_cl.cd_lu_dev); } static inline struct cl_device *lovsub2cl_dev(struct lovsub_device *lovsub) @@ -512,13 +512,13 @@ static inline struct lu_device *lovsub2lu_dev(struct lovsub_device *lovsub) static inline struct lovsub_device *lu2lovsub_dev(const struct lu_device *d) { LINVRNT(d->ld_type == &lovsub_device_type); - return container_of0(d, struct lovsub_device, acid_cl.cd_lu_dev); + return container_of(d, struct lovsub_device, acid_cl.cd_lu_dev); } static inline struct lovsub_device *cl2lovsub_dev(const struct cl_device *d) { LINVRNT(d->cd_lu_dev.ld_type == &lovsub_device_type); - return container_of0(d, struct lovsub_device, acid_cl); + return container_of(d, struct lovsub_device, acid_cl); } static inline struct lu_object *lov2lu(struct lov_object *lov) @@ -534,13 +534,13 @@ static inline struct cl_object *lov2cl(struct lov_object *lov) static inline struct lov_object *lu2lov(const struct lu_object *obj) { LINVRNT(lov_is_object(obj)); - return container_of0(obj, struct lov_object, lo_cl.co_lu); + return container_of(obj, struct lov_object, lo_cl.co_lu); } static inline struct lov_object *cl2lov(const struct cl_object *obj) { LINVRNT(lov_is_object(&obj->co_lu)); - return container_of0(obj, struct lov_object, lo_cl); + return container_of(obj, struct lov_object, lo_cl); } static inline struct lu_object *lovsub2lu(struct lovsub_object *los) @@ -556,13 +556,13 @@ static inline struct cl_object *lovsub2cl(struct lovsub_object *los) static inline struct lovsub_object *cl2lovsub(const struct cl_object *obj) { LINVRNT(lovsub_is_object(&obj->co_lu)); - return container_of0(obj, struct lovsub_object, lso_cl); + return container_of(obj, struct lovsub_object, lso_cl); } static inline struct lovsub_object *lu2lovsub(const struct lu_object *obj) { LINVRNT(lovsub_is_object(obj)); - return container_of0(obj, struct lovsub_object, lso_cl.co_lu); + return container_of(obj, struct lovsub_object, lso_cl.co_lu); } static inline struct lovsub_lock * @@ -590,14 +590,14 @@ static inline struct lov_lock *cl2lov_lock(const struct cl_lock_slice *slice) static inline struct lov_page *cl2lov_page(const struct cl_page_slice *slice) { LINVRNT(lov_is_object(&slice->cpl_obj->co_lu)); - return container_of0(slice, struct lov_page, lps_cl); + return container_of(slice, struct lov_page, lps_cl); } static inline struct lovsub_page * cl2lovsub_page(const struct cl_page_slice *slice) { LINVRNT(lovsub_is_object(&slice->cpl_obj->co_lu)); - return container_of0(slice, struct lovsub_page, lsb_cl); + return container_of(slice, struct lovsub_page, lsb_cl); } static inline struct lov_io *cl2lov_io(const struct lu_env *env, diff --git a/drivers/staging/lustre/lustre/lov/lov_internal.h b/drivers/staging/lustre/lustre/lov/lov_internal.h index 8dde3828f935..47042f27ca90 100644 --- a/drivers/staging/lustre/lustre/lov/lov_internal.h +++ b/drivers/staging/lustre/lustre/lov/lov_internal.h @@ -280,7 +280,7 @@ static inline bool lov_oinfo_is_dummy(const struct lov_oinfo *loi) static inline struct obd_device *lov2obd(const struct lov_obd *lov) { - return container_of0(lov, struct obd_device, u.lov); + return container_of_safe(lov, struct obd_device, u.lov); } #endif diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c index 3ae16e8501c2..3de7dc0497c4 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c @@ -319,7 +319,7 @@ static void lu_object_free(const struct lu_env *env, struct lu_object *o) * lives as long as possible and ->loo_object_free() methods * can look at its contents. */ - o = container_of0(splice.prev, struct lu_object, lo_linkage); + o = container_of(splice.prev, struct lu_object, lo_linkage); list_del_init(&o->lo_linkage); o->lo_ops->loo_object_free(env, o); } @@ -404,8 +404,8 @@ int lu_site_purge_objects(const struct lu_env *env, struct lu_site *s, * races due to the reasons described in lu_object_put(). */ while (!list_empty(&dispose)) { - h = container_of0(dispose.next, - struct lu_object_header, loh_lru); + h = container_of(dispose.next, + struct lu_object_header, loh_lru); list_del_init(&h->loh_lru); lu_object_free(env, lu_object_top(h)); lprocfs_counter_incr(s->ls_stats, LU_SS_LRU_PURGED); @@ -579,7 +579,7 @@ static struct lu_object *htable_lookup(struct lu_site *s, return ERR_PTR(-ENOENT); } - h = container_of0(hnode, struct lu_object_header, loh_hash); + h = container_of(hnode, struct lu_object_header, loh_hash); if (likely(!lu_object_is_dying(h))) { cfs_hash_get(s->ls_obj_hash, hnode); lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_HIT); diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c index 99a76db51ae0..767067b61109 100644 --- a/drivers/staging/lustre/lustre/obdecho/echo_client.c +++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c @@ -99,7 +99,7 @@ static int echo_client_cleanup(struct obd_device *obddev); */ static inline struct echo_device *cl2echo_dev(const struct cl_device *dev) { - return container_of0(dev, struct echo_device, ed_cl); + return container_of_safe(dev, struct echo_device, ed_cl); } static inline struct cl_device *echo_dev2cl(struct echo_device *d) diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h index 1449013722f6..dc25dd12d7d5 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h @@ -460,7 +460,7 @@ static inline int osc_is_object(const struct lu_object *obj) static inline struct osc_device *lu2osc_dev(const struct lu_device *d) { LINVRNT(d->ld_type == &osc_device_type); - return container_of0(d, struct osc_device, od_cl.cd_lu_dev); + return container_of(d, struct osc_device, od_cl.cd_lu_dev); } static inline struct obd_export *osc_export(const struct osc_object *obj) @@ -476,7 +476,7 @@ static inline struct client_obd *osc_cli(const struct osc_object *obj) static inline struct osc_object *cl2osc(const struct cl_object *obj) { LINVRNT(osc_is_object(&obj->co_lu)); - return container_of0(obj, struct osc_object, oo_cl); + return container_of(obj, struct osc_object, oo_cl); } static inline struct cl_object *osc2cl(const struct osc_object *obj) @@ -509,12 +509,12 @@ static inline enum cl_lock_mode osc_ldlm2cl_lock(enum ldlm_mode mode) static inline struct osc_page *cl2osc_page(const struct cl_page_slice *slice) { LINVRNT(osc_is_object(&slice->cpl_obj->co_lu)); - return container_of0(slice, struct osc_page, ops_cl); + return container_of(slice, struct osc_page, ops_cl); } static inline struct osc_page *oap2osc(struct osc_async_page *oap) { - return container_of0(oap, struct osc_page, ops_oap); + return container_of_safe(oap, struct osc_page, ops_oap); } static inline pgoff_t osc_index(struct osc_page *opg) @@ -545,7 +545,7 @@ osc_cl_page_osc(struct cl_page *page, struct osc_object *osc) static inline struct osc_lock *cl2osc_lock(const struct cl_lock_slice *slice) { LINVRNT(osc_is_object(&slice->cls_obj->co_lu)); - return container_of0(slice, struct osc_lock, ols_cl); + return container_of(slice, struct osc_lock, ols_cl); } static inline struct osc_lock *osc_lock_at(const struct cl_lock *lock) diff --git a/drivers/staging/lustre/lustre/osc/osc_internal.h b/drivers/staging/lustre/lustre/osc/osc_internal.h index 1c8ba4ad6e7f..fca020568c19 100644 --- a/drivers/staging/lustre/lustre/osc/osc_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_internal.h @@ -180,7 +180,7 @@ struct osc_device { static inline struct osc_device *obd2osc_dev(const struct obd_device *d) { - return container_of0(d->obd_lu_dev, struct osc_device, od_cl.cd_lu_dev); + return container_of_safe(d->obd_lu_dev, struct osc_device, od_cl.cd_lu_dev); } extern struct lu_kmem_descr osc_caches[]; diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c index 76743faf3e6d..67734a8ed331 100644 --- a/drivers/staging/lustre/lustre/osc/osc_io.c +++ b/drivers/staging/lustre/lustre/osc/osc_io.c @@ -55,7 +55,7 @@ static struct osc_io *cl2osc_io(const struct lu_env *env, const struct cl_io_slice *slice) { - struct osc_io *oio = container_of0(slice, struct osc_io, oi_cl); + struct osc_io *oio = container_of_safe(slice, struct osc_io, oi_cl); LINVRNT(oio == osc_env_io(env)); return oio; diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c index 4f81dd16f4f5..84240181c7ea 100644 --- a/drivers/staging/lustre/lustre/osc/osc_object.c +++ b/drivers/staging/lustre/lustre/osc/osc_object.c @@ -58,7 +58,7 @@ static struct lu_object *osc2lu(struct osc_object *osc) static struct osc_object *lu2osc(const struct lu_object *obj) { LINVRNT(osc_is_object(obj)); - return container_of0(obj, struct osc_object, oo_cl.co_lu); + return container_of(obj, struct osc_object, oo_cl.co_lu); } /***************************************************************************** diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 6a1eb0b0aad9..58d6645b1425 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -964,6 +964,22 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { } "pointer type mismatch in container_of()"); \ ((type *)(__mptr - offsetof(type, member))); }) +/** + * container_of_safe - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + * If IS_ERR_OR_NULL(ptr), ptr is returned unchanged. + */ +#define container_of_safe(ptr, type, member) ({ \ + void *__mptr = (void *)(ptr); \ + BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \ + !__same_type(*(ptr), void), \ + "pointer type mismatch in container_of()"); \ + IS_ERR_OR_NULL(ptr) ? ERR_CAST(ptr) : \ + ((type *)(__mptr - offsetof(type, member))); }) + /* Rebuild everything on CONFIG_FTRACE_MCOUNT_RECORD */ #ifdef CONFIG_FTRACE_MCOUNT_RECORD # define REBUILD_DUE_TO_FTRACE_MCOUNT_RECORD -- cgit v1.2.3-71-gd317 From 227abcc6da7b803e380f034d6772ea0861612340 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 26 Apr 2018 08:58:27 +0300 Subject: staging: kernel.h: Prevent macro expantion bug in container_of_safe() There aren't many users of this so it doesn't cause a problem, but we obviously want to use "__mptr" here instead of "ptr" to prevent the parameter from being executed twice. Signed-off-by: Dan Carpenter Acked-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- include/linux/kernel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 58d6645b1425..3dfa3f260fc4 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -977,7 +977,7 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { } BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \ !__same_type(*(ptr), void), \ "pointer type mismatch in container_of()"); \ - IS_ERR_OR_NULL(ptr) ? ERR_CAST(ptr) : \ + IS_ERR_OR_NULL(__mptr) ? ERR_CAST(__mptr) : \ ((type *)(__mptr - offsetof(type, member))); }) /* Rebuild everything on CONFIG_FTRACE_MCOUNT_RECORD */ -- cgit v1.2.3-71-gd317 From 04e7b3d7eabefa0807b398233f019f274945ee79 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 7 May 2018 06:35:51 -0300 Subject: iio: iio.h: use nested struct support on kernel-doc markup Solve those Sphinx warnings: ./include/linux/iio/iio.h:270: warning: Function parameter or member 'scan_type.sign' not described in 'iio_chan_spec' ./include/linux/iio/iio.h:270: warning: Function parameter or member 'scan_type.realbits' not described in 'iio_chan_spec' ./include/linux/iio/iio.h:270: warning: Function parameter or member 'scan_type.storagebits' not described in 'iio_chan_spec' ./include/linux/iio/iio.h:270: warning: Function parameter or member 'scan_type.shift' not described in 'iio_chan_spec' ./include/linux/iio/iio.h:270: warning: Function parameter or member 'scan_type.repeat' not described in 'iio_chan_spec' ./include/linux/iio/iio.h:270: warning: Function parameter or member 'scan_type.endianness' not described in 'iio_chan_spec' ./include/linux/iio/iio.h:191: WARNING: Unexpected indentation. ./include/linux/iio/iio.h:192: WARNING: Block quote ends without a blank line; unexpected unindent. ./include/linux/iio/iio.h:198: WARNING: Definition list ends without a blank line; unexpected unindent. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Cameron --- include/linux/iio/iio.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 11579fd4126e..a74cb177dc6f 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -183,18 +183,18 @@ struct iio_event_spec { * @address: Driver specific identifier. * @scan_index: Monotonic index to give ordering in scans when read * from a buffer. - * @scan_type: sign: 's' or 'u' to specify signed or unsigned - * realbits: Number of valid bits of data - * storagebits: Realbits + padding - * shift: Shift right by this before masking out - * realbits. - * repeat: Number of times real/storage bits - * repeats. When the repeat element is - * more than 1, then the type element in - * sysfs will show a repeat value. - * Otherwise, the number of repetitions is - * omitted. - * endianness: little or big endian + * @scan_type: struct describing the scan type + * @scan_type.sign: 's' or 'u' to specify signed or unsigned + * @scan_type.realbits: Number of valid bits of data + * @scan_type.storagebits: Realbits + padding + * @scan_type.shift: Shift right by this before masking out + * realbits. + * @scan_type.repeat: Number of times real/storage bits repeats. + * When the repeat element is more than 1, then + * the type element in sysfs will show a repeat + * value. Otherwise, the number of repetitions + * is omitted. + * @scan_type.endianness: little or big endian * @info_mask_separate: What information is to be exported that is specific to * this channel. * @info_mask_separate_available: What availability information is to be -- cgit v1.2.3-71-gd317 From c06c4d793584b965bf5fa3fb107f6279643574e2 Mon Sep 17 00:00:00 2001 From: Brian Masney Date: Thu, 10 May 2018 20:12:23 -0400 Subject: staging: iio: tsl2x7x/tsl2772: move out of staging Move the tsl2772 driver out of staging and into mainline. Signed-off-by: Brian Masney Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 8 + drivers/iio/light/Makefile | 1 + drivers/iio/light/tsl2772.c | 1800 +++++++++++++++++++++++++++++++++ drivers/staging/iio/Kconfig | 1 - drivers/staging/iio/Makefile | 1 - drivers/staging/iio/light/Kconfig | 14 - drivers/staging/iio/light/Makefile | 5 - drivers/staging/iio/light/tsl2772.c | 1800 --------------------------------- drivers/staging/iio/light/tsl2772.h | 101 -- include/linux/platform_data/tsl2772.h | 101 ++ 10 files changed, 1910 insertions(+), 1922 deletions(-) create mode 100644 drivers/iio/light/tsl2772.c delete mode 100644 drivers/staging/iio/light/Kconfig delete mode 100644 drivers/staging/iio/light/Makefile delete mode 100644 drivers/staging/iio/light/tsl2772.c delete mode 100644 drivers/staging/iio/light/tsl2772.h create mode 100644 include/linux/platform_data/tsl2772.h (limited to 'include') diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 074e50657366..c7ef8d1862d6 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -409,6 +409,14 @@ config TSL2583 Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices. Access ALS data via iio, sysfs. +config TSL2772 + tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors" + depends on I2C + help + Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672, + tmd2672, tsl2772, tmd2772 devices. + Provides iio_events and direct access via sysfs. + config TSL4531 tristate "TAOS TSL4531 ambient light sensors" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index f1777036d4f8..80943af5d627 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_ST_UVIS25_SPI) += st_uvis25_spi.o obj-$(CONFIG_TCS3414) += tcs3414.o obj-$(CONFIG_TCS3472) += tcs3472.o obj-$(CONFIG_TSL2583) += tsl2583.o +obj-$(CONFIG_TSL2772) += tsl2772.o obj-$(CONFIG_TSL4531) += tsl4531.o obj-$(CONFIG_US5182D) += us5182d.o obj-$(CONFIG_VCNL4000) += vcnl4000.o diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c new file mode 100644 index 000000000000..34d42a2504c9 --- /dev/null +++ b/drivers/iio/light/tsl2772.c @@ -0,0 +1,1800 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Device driver for monitoring ambient light intensity in (lux) and proximity + * detection (prox) within the TAOS TSL2571, TSL2671, TMD2671, TSL2771, TMD2771, + * TSL2572, TSL2672, TMD2672, TSL2772, and TMD2772 devices. + * + * Copyright (c) 2012, TAOS Corporation. + * Copyright (c) 2017-2018 Brian Masney + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Cal defs */ +#define PROX_STAT_CAL 0 +#define PROX_STAT_SAMP 1 +#define MAX_SAMPLES_CAL 200 + +/* TSL2772 Device ID */ +#define TRITON_ID 0x00 +#define SWORDFISH_ID 0x30 +#define HALIBUT_ID 0x20 + +/* Lux calculation constants */ +#define TSL2772_LUX_CALC_OVER_FLOW 65535 + +/* + * TAOS Register definitions - Note: depending on device, some of these register + * are not used and the register address is benign. + */ + +/* Register offsets */ +#define TSL2772_MAX_CONFIG_REG 16 + +/* Device Registers and Masks */ +#define TSL2772_CNTRL 0x00 +#define TSL2772_ALS_TIME 0X01 +#define TSL2772_PRX_TIME 0x02 +#define TSL2772_WAIT_TIME 0x03 +#define TSL2772_ALS_MINTHRESHLO 0X04 +#define TSL2772_ALS_MINTHRESHHI 0X05 +#define TSL2772_ALS_MAXTHRESHLO 0X06 +#define TSL2772_ALS_MAXTHRESHHI 0X07 +#define TSL2772_PRX_MINTHRESHLO 0X08 +#define TSL2772_PRX_MINTHRESHHI 0X09 +#define TSL2772_PRX_MAXTHRESHLO 0X0A +#define TSL2772_PRX_MAXTHRESHHI 0X0B +#define TSL2772_PERSISTENCE 0x0C +#define TSL2772_ALS_PRX_CONFIG 0x0D +#define TSL2772_PRX_COUNT 0x0E +#define TSL2772_GAIN 0x0F +#define TSL2772_NOTUSED 0x10 +#define TSL2772_REVID 0x11 +#define TSL2772_CHIPID 0x12 +#define TSL2772_STATUS 0x13 +#define TSL2772_ALS_CHAN0LO 0x14 +#define TSL2772_ALS_CHAN0HI 0x15 +#define TSL2772_ALS_CHAN1LO 0x16 +#define TSL2772_ALS_CHAN1HI 0x17 +#define TSL2772_PRX_LO 0x18 +#define TSL2772_PRX_HI 0x19 + +/* tsl2772 cmd reg masks */ +#define TSL2772_CMD_REG 0x80 +#define TSL2772_CMD_SPL_FN 0x60 +#define TSL2772_CMD_REPEAT_PROTO 0x00 +#define TSL2772_CMD_AUTOINC_PROTO 0x20 + +#define TSL2772_CMD_PROX_INT_CLR 0X05 +#define TSL2772_CMD_ALS_INT_CLR 0x06 +#define TSL2772_CMD_PROXALS_INT_CLR 0X07 + +/* tsl2772 cntrl reg masks */ +#define TSL2772_CNTL_ADC_ENBL 0x02 +#define TSL2772_CNTL_PWR_ON 0x01 + +/* tsl2772 status reg masks */ +#define TSL2772_STA_ADC_VALID 0x01 +#define TSL2772_STA_PRX_VALID 0x02 +#define TSL2772_STA_ADC_PRX_VALID (TSL2772_STA_ADC_VALID | \ + TSL2772_STA_PRX_VALID) +#define TSL2772_STA_ALS_INTR 0x10 +#define TSL2772_STA_PRX_INTR 0x20 + +/* tsl2772 cntrl reg masks */ +#define TSL2772_CNTL_REG_CLEAR 0x00 +#define TSL2772_CNTL_PROX_INT_ENBL 0X20 +#define TSL2772_CNTL_ALS_INT_ENBL 0X10 +#define TSL2772_CNTL_WAIT_TMR_ENBL 0X08 +#define TSL2772_CNTL_PROX_DET_ENBL 0X04 +#define TSL2772_CNTL_PWRON 0x01 +#define TSL2772_CNTL_ALSPON_ENBL 0x03 +#define TSL2772_CNTL_INTALSPON_ENBL 0x13 +#define TSL2772_CNTL_PROXPON_ENBL 0x0F +#define TSL2772_CNTL_INTPROXPON_ENBL 0x2F + +#define TSL2772_ALS_GAIN_TRIM_MIN 250 +#define TSL2772_ALS_GAIN_TRIM_MAX 4000 + +/* Device family members */ +enum { + tsl2571, + tsl2671, + tmd2671, + tsl2771, + tmd2771, + tsl2572, + tsl2672, + tmd2672, + tsl2772, + tmd2772 +}; + +enum { + TSL2772_CHIP_UNKNOWN = 0, + TSL2772_CHIP_WORKING = 1, + TSL2772_CHIP_SUSPENDED = 2 +}; + +/* Per-device data */ +struct tsl2772_als_info { + u16 als_ch0; + u16 als_ch1; + u16 lux; +}; + +struct tsl2772_chip_info { + int chan_table_elements; + struct iio_chan_spec channel_with_events[4]; + struct iio_chan_spec channel_without_events[4]; + const struct iio_info *info; +}; + +struct tsl2772_chip { + kernel_ulong_t id; + struct mutex prox_mutex; + struct mutex als_mutex; + struct i2c_client *client; + u16 prox_data; + struct tsl2772_als_info als_cur_info; + struct tsl2772_settings settings; + struct tsl2772_platform_data *pdata; + int als_gain_time_scale; + int als_saturation; + int tsl2772_chip_status; + u8 tsl2772_config[TSL2772_MAX_CONFIG_REG]; + const struct tsl2772_chip_info *chip_info; + const struct iio_info *info; + s64 event_timestamp; + /* + * This structure is intentionally large to accommodate + * updates via sysfs. + * Sized to 9 = max 8 segments + 1 termination segment + */ + struct tsl2772_lux tsl2772_device_lux[TSL2772_MAX_LUX_TABLE_SIZE]; +}; + +/* + * Different devices require different coefficents, and these numbers were + * derived from the 'Lux Equation' section of the various device datasheets. + * All of these coefficients assume a Glass Attenuation (GA) factor of 1. + * The coefficients are multiplied by 1000 to avoid floating point operations. + * The two rows in each table correspond to the Lux1 and Lux2 equations from + * the datasheets. + */ +static const struct tsl2772_lux tsl2x71_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { + { 53000, 106000 }, + { 31800, 53000 }, + { 0, 0 }, +}; + +static const struct tsl2772_lux tmd2x71_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { + { 24000, 48000 }, + { 14400, 24000 }, + { 0, 0 }, +}; + +static const struct tsl2772_lux tsl2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { + { 60000, 112200 }, + { 37800, 60000 }, + { 0, 0 }, +}; + +static const struct tsl2772_lux tmd2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { + { 20000, 35000 }, + { 12600, 20000 }, + { 0, 0 }, +}; + +static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = { + [tsl2571] = tsl2x71_lux_table, + [tsl2671] = tsl2x71_lux_table, + [tmd2671] = tmd2x71_lux_table, + [tsl2771] = tsl2x71_lux_table, + [tmd2771] = tmd2x71_lux_table, + [tsl2572] = tsl2x72_lux_table, + [tsl2672] = tsl2x72_lux_table, + [tmd2672] = tmd2x72_lux_table, + [tsl2772] = tsl2x72_lux_table, + [tmd2772] = tmd2x72_lux_table, +}; + +static const struct tsl2772_settings tsl2772_default_settings = { + .als_time = 255, /* 2.72 / 2.73 ms */ + .als_gain = 0, + .prox_time = 255, /* 2.72 / 2.73 ms */ + .prox_gain = 0, + .wait_time = 255, + .als_prox_config = 0, + .als_gain_trim = 1000, + .als_cal_target = 150, + .als_persistence = 1, + .als_interrupt_en = false, + .als_thresh_low = 200, + .als_thresh_high = 256, + .prox_persistence = 1, + .prox_interrupt_en = false, + .prox_thres_low = 0, + .prox_thres_high = 512, + .prox_max_samples_cal = 30, + .prox_pulse_count = 8, + .prox_diode = TSL2772_DIODE1, + .prox_power = TSL2772_100_mA +}; + +static const s16 tsl2772_als_gain[] = { + 1, + 8, + 16, + 120 +}; + +static const s16 tsl2772_prox_gain[] = { + 1, + 2, + 4, + 8 +}; + +static const int tsl2772_int_time_avail[][6] = { + [tsl2571] = { 0, 2720, 0, 2720, 0, 696000 }, + [tsl2671] = { 0, 2720, 0, 2720, 0, 696000 }, + [tmd2671] = { 0, 2720, 0, 2720, 0, 696000 }, + [tsl2771] = { 0, 2720, 0, 2720, 0, 696000 }, + [tmd2771] = { 0, 2720, 0, 2720, 0, 696000 }, + [tsl2572] = { 0, 2730, 0, 2730, 0, 699000 }, + [tsl2672] = { 0, 2730, 0, 2730, 0, 699000 }, + [tmd2672] = { 0, 2730, 0, 2730, 0, 699000 }, + [tsl2772] = { 0, 2730, 0, 2730, 0, 699000 }, + [tmd2772] = { 0, 2730, 0, 2730, 0, 699000 }, +}; + +static int tsl2772_int_calibscale_avail[] = { 1, 8, 16, 120 }; + +static int tsl2772_prox_calibscale_avail[] = { 1, 2, 4, 8 }; + +/* Channel variations */ +enum { + ALS, + PRX, + ALSPRX, + PRX2, + ALSPRX2, +}; + +static const u8 device_channel_config[] = { + [tsl2571] = ALS, + [tsl2671] = PRX, + [tmd2671] = PRX, + [tsl2771] = ALSPRX, + [tmd2771] = ALSPRX, + [tsl2572] = ALS, + [tsl2672] = PRX2, + [tmd2672] = PRX2, + [tsl2772] = ALSPRX2, + [tmd2772] = ALSPRX2 +}; + +static int tsl2772_read_status(struct tsl2772_chip *chip) +{ + int ret; + + ret = i2c_smbus_read_byte_data(chip->client, + TSL2772_CMD_REG | TSL2772_STATUS); + if (ret < 0) + dev_err(&chip->client->dev, + "%s: failed to read STATUS register: %d\n", __func__, + ret); + + return ret; +} + +static int tsl2772_write_control_reg(struct tsl2772_chip *chip, u8 data) +{ + int ret; + + ret = i2c_smbus_write_byte_data(chip->client, + TSL2772_CMD_REG | TSL2772_CNTRL, data); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to write to control register %x: %d\n", + __func__, data, ret); + } + + return ret; +} + +static int tsl2772_read_autoinc_regs(struct tsl2772_chip *chip, int lower_reg, + int upper_reg) +{ + u8 buf[2]; + int ret; + + ret = i2c_smbus_write_byte(chip->client, + TSL2772_CMD_REG | TSL2772_CMD_AUTOINC_PROTO | + lower_reg); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to enable auto increment protocol: %d\n", + __func__, ret); + return ret; + } + + ret = i2c_smbus_read_byte_data(chip->client, + TSL2772_CMD_REG | lower_reg); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to read from register %x: %d\n", __func__, + lower_reg, ret); + return ret; + } + buf[0] = ret; + + ret = i2c_smbus_read_byte_data(chip->client, + TSL2772_CMD_REG | upper_reg); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to read from register %x: %d\n", __func__, + upper_reg, ret); + return ret; + } + buf[1] = ret; + + ret = i2c_smbus_write_byte(chip->client, + TSL2772_CMD_REG | TSL2772_CMD_REPEAT_PROTO | + lower_reg); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to enable repeated byte protocol: %d\n", + __func__, ret); + return ret; + } + + return le16_to_cpup((const __le16 *)&buf[0]); +} + +/** + * tsl2772_get_lux() - Reads and calculates current lux value. + * @indio_dev: pointer to IIO device + * + * The raw ch0 and ch1 values of the ambient light sensed in the last + * integration cycle are read from the device. The raw values are multiplied + * by a device-specific scale factor, and divided by the integration time and + * device gain. The code supports multiple lux equations through the lux table + * coefficients. A lux gain trim is applied to each lux equation, and then the + * maximum lux within the interval 0..65535 is selected. + */ +static int tsl2772_get_lux(struct iio_dev *indio_dev) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + struct tsl2772_lux *p; + int max_lux, ret; + bool overflow; + + mutex_lock(&chip->als_mutex); + + if (chip->tsl2772_chip_status != TSL2772_CHIP_WORKING) { + dev_err(&chip->client->dev, "%s: device is not enabled\n", + __func__); + ret = -EBUSY; + goto out_unlock; + } + + ret = tsl2772_read_status(chip); + if (ret < 0) + goto out_unlock; + + if (!(ret & TSL2772_STA_ADC_VALID)) { + dev_err(&chip->client->dev, + "%s: data not valid yet\n", __func__); + ret = chip->als_cur_info.lux; /* return LAST VALUE */ + goto out_unlock; + } + + ret = tsl2772_read_autoinc_regs(chip, TSL2772_ALS_CHAN0LO, + TSL2772_ALS_CHAN0HI); + if (ret < 0) + goto out_unlock; + chip->als_cur_info.als_ch0 = ret; + + ret = tsl2772_read_autoinc_regs(chip, TSL2772_ALS_CHAN1LO, + TSL2772_ALS_CHAN1HI); + if (ret < 0) + goto out_unlock; + chip->als_cur_info.als_ch1 = ret; + + if (chip->als_cur_info.als_ch0 >= chip->als_saturation) { + max_lux = TSL2772_LUX_CALC_OVER_FLOW; + goto update_struct_with_max_lux; + } + + if (!chip->als_cur_info.als_ch0) { + /* have no data, so return LAST VALUE */ + ret = chip->als_cur_info.lux; + goto out_unlock; + } + + max_lux = 0; + overflow = false; + for (p = (struct tsl2772_lux *)chip->tsl2772_device_lux; p->ch0 != 0; + p++) { + int lux; + + lux = ((chip->als_cur_info.als_ch0 * p->ch0) - + (chip->als_cur_info.als_ch1 * p->ch1)) / + chip->als_gain_time_scale; + + /* + * The als_gain_trim can have a value within the range 250..4000 + * and is a multiplier for the lux. A trim of 1000 makes no + * changes to the lux, less than 1000 scales it down, and + * greater than 1000 scales it up. + */ + lux = (lux * chip->settings.als_gain_trim) / 1000; + + if (lux > TSL2772_LUX_CALC_OVER_FLOW) { + overflow = true; + continue; + } + + max_lux = max(max_lux, lux); + } + + if (overflow && max_lux == 0) + max_lux = TSL2772_LUX_CALC_OVER_FLOW; + +update_struct_with_max_lux: + chip->als_cur_info.lux = max_lux; + ret = max_lux; + +out_unlock: + mutex_unlock(&chip->als_mutex); + + return ret; +} + +/** + * tsl2772_get_prox() - Reads proximity data registers and updates + * chip->prox_data. + * + * @indio_dev: pointer to IIO device + */ +static int tsl2772_get_prox(struct iio_dev *indio_dev) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + int ret; + + mutex_lock(&chip->prox_mutex); + + ret = tsl2772_read_status(chip); + if (ret < 0) + goto prox_poll_err; + + switch (chip->id) { + case tsl2571: + case tsl2671: + case tmd2671: + case tsl2771: + case tmd2771: + if (!(ret & TSL2772_STA_ADC_VALID)) { + ret = -EINVAL; + goto prox_poll_err; + } + break; + case tsl2572: + case tsl2672: + case tmd2672: + case tsl2772: + case tmd2772: + if (!(ret & TSL2772_STA_PRX_VALID)) { + ret = -EINVAL; + goto prox_poll_err; + } + break; + } + + ret = tsl2772_read_autoinc_regs(chip, TSL2772_PRX_LO, TSL2772_PRX_HI); + if (ret < 0) + goto prox_poll_err; + chip->prox_data = ret; + +prox_poll_err: + mutex_unlock(&chip->prox_mutex); + + return ret; +} + +/** + * tsl2772_defaults() - Populates the device nominal operating parameters + * with those provided by a 'platform' data struct or + * with prefined defaults. + * + * @chip: pointer to device structure. + */ +static void tsl2772_defaults(struct tsl2772_chip *chip) +{ + /* If Operational settings defined elsewhere.. */ + if (chip->pdata && chip->pdata->platform_default_settings) + memcpy(&chip->settings, chip->pdata->platform_default_settings, + sizeof(tsl2772_default_settings)); + else + memcpy(&chip->settings, &tsl2772_default_settings, + sizeof(tsl2772_default_settings)); + + /* Load up the proper lux table. */ + if (chip->pdata && chip->pdata->platform_lux_table[0].ch0 != 0) + memcpy(chip->tsl2772_device_lux, + chip->pdata->platform_lux_table, + sizeof(chip->pdata->platform_lux_table)); + else + memcpy(chip->tsl2772_device_lux, + tsl2772_default_lux_table_group[chip->id], + TSL2772_DEFAULT_TABLE_BYTES); +} + +/** + * tsl2772_als_calibrate() - Obtain single reading and calculate + * the als_gain_trim. + * + * @indio_dev: pointer to IIO device + */ +static int tsl2772_als_calibrate(struct iio_dev *indio_dev) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + int ret, lux_val; + + ret = i2c_smbus_read_byte_data(chip->client, + TSL2772_CMD_REG | TSL2772_CNTRL); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to read from the CNTRL register\n", + __func__); + return ret; + } + + if ((ret & (TSL2772_CNTL_ADC_ENBL | TSL2772_CNTL_PWR_ON)) + != (TSL2772_CNTL_ADC_ENBL | TSL2772_CNTL_PWR_ON)) { + dev_err(&chip->client->dev, + "%s: Device is not powered on and/or ADC is not enabled\n", + __func__); + return -EINVAL; + } else if ((ret & TSL2772_STA_ADC_VALID) != TSL2772_STA_ADC_VALID) { + dev_err(&chip->client->dev, + "%s: The two ADC channels have not completed an integration cycle\n", + __func__); + return -ENODATA; + } + + lux_val = tsl2772_get_lux(indio_dev); + if (lux_val < 0) { + dev_err(&chip->client->dev, + "%s: failed to get lux\n", __func__); + return lux_val; + } + + ret = (chip->settings.als_cal_target * chip->settings.als_gain_trim) / + lux_val; + if (ret < TSL2772_ALS_GAIN_TRIM_MIN || ret > TSL2772_ALS_GAIN_TRIM_MAX) + return -ERANGE; + + chip->settings.als_gain_trim = ret; + + return ret; +} + +static int tsl2772_chip_on(struct iio_dev *indio_dev) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + int ret, i, als_count, als_time_us; + u8 *dev_reg, reg_val; + + /* Non calculated parameters */ + chip->tsl2772_config[TSL2772_ALS_TIME] = chip->settings.als_time; + chip->tsl2772_config[TSL2772_PRX_TIME] = chip->settings.prox_time; + chip->tsl2772_config[TSL2772_WAIT_TIME] = chip->settings.wait_time; + chip->tsl2772_config[TSL2772_ALS_PRX_CONFIG] = + chip->settings.als_prox_config; + + chip->tsl2772_config[TSL2772_ALS_MINTHRESHLO] = + (chip->settings.als_thresh_low) & 0xFF; + chip->tsl2772_config[TSL2772_ALS_MINTHRESHHI] = + (chip->settings.als_thresh_low >> 8) & 0xFF; + chip->tsl2772_config[TSL2772_ALS_MAXTHRESHLO] = + (chip->settings.als_thresh_high) & 0xFF; + chip->tsl2772_config[TSL2772_ALS_MAXTHRESHHI] = + (chip->settings.als_thresh_high >> 8) & 0xFF; + chip->tsl2772_config[TSL2772_PERSISTENCE] = + (chip->settings.prox_persistence & 0xFF) << 4 | + (chip->settings.als_persistence & 0xFF); + + chip->tsl2772_config[TSL2772_PRX_COUNT] = + chip->settings.prox_pulse_count; + chip->tsl2772_config[TSL2772_PRX_MINTHRESHLO] = + (chip->settings.prox_thres_low) & 0xFF; + chip->tsl2772_config[TSL2772_PRX_MINTHRESHHI] = + (chip->settings.prox_thres_low >> 8) & 0xFF; + chip->tsl2772_config[TSL2772_PRX_MAXTHRESHLO] = + (chip->settings.prox_thres_high) & 0xFF; + chip->tsl2772_config[TSL2772_PRX_MAXTHRESHHI] = + (chip->settings.prox_thres_high >> 8) & 0xFF; + + /* and make sure we're not already on */ + if (chip->tsl2772_chip_status == TSL2772_CHIP_WORKING) { + /* if forcing a register update - turn off, then on */ + dev_info(&chip->client->dev, "device is already enabled\n"); + return -EINVAL; + } + + /* Set the gain based on tsl2772_settings struct */ + chip->tsl2772_config[TSL2772_GAIN] = + (chip->settings.als_gain & 0xFF) | + ((chip->settings.prox_gain & 0xFF) << 2) | + (chip->settings.prox_diode << 4) | + (chip->settings.prox_power << 6); + + /* set chip time scaling and saturation */ + als_count = 256 - chip->settings.als_time; + als_time_us = als_count * tsl2772_int_time_avail[chip->id][3]; + chip->als_saturation = als_count * 768; /* 75% of full scale */ + chip->als_gain_time_scale = als_time_us * + tsl2772_als_gain[chip->settings.als_gain]; + + /* + * TSL2772 Specific power-on / adc enable sequence + * Power on the device 1st. + */ + ret = tsl2772_write_control_reg(chip, TSL2772_CNTL_PWR_ON); + if (ret < 0) + return ret; + + /* + * Use the following shadow copy for our delay before enabling ADC. + * Write all the registers. + */ + for (i = 0, dev_reg = chip->tsl2772_config; + i < TSL2772_MAX_CONFIG_REG; i++) { + int reg = TSL2772_CMD_REG + i; + + ret = i2c_smbus_write_byte_data(chip->client, reg, + *dev_reg++); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to write to register %x: %d\n", + __func__, reg, ret); + return ret; + } + } + + /* Power-on settling time */ + usleep_range(3000, 3500); + + reg_val = TSL2772_CNTL_PWR_ON | TSL2772_CNTL_ADC_ENBL | + TSL2772_CNTL_PROX_DET_ENBL; + if (chip->settings.als_interrupt_en) + reg_val |= TSL2772_CNTL_ALS_INT_ENBL; + if (chip->settings.prox_interrupt_en) + reg_val |= TSL2772_CNTL_PROX_INT_ENBL; + + ret = tsl2772_write_control_reg(chip, reg_val); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte(chip->client, + TSL2772_CMD_REG | TSL2772_CMD_SPL_FN | + TSL2772_CMD_PROXALS_INT_CLR); + if (ret < 0) { + dev_err(&chip->client->dev, + "%s: failed to clear interrupt status: %d\n", + __func__, ret); + return ret; + } + + chip->tsl2772_chip_status = TSL2772_CHIP_WORKING; + + return ret; +} + +static int tsl2772_chip_off(struct iio_dev *indio_dev) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + + /* turn device off */ + chip->tsl2772_chip_status = TSL2772_CHIP_SUSPENDED; + return tsl2772_write_control_reg(chip, 0x00); +} + +/** + * tsl2772_invoke_change - power cycle the device to implement the user + * parameters + * @indio_dev: pointer to IIO device + * + * Obtain and lock both ALS and PROX resources, determine and save device state + * (On/Off), cycle device to implement updated parameter, put device back into + * proper state, and unlock resource. + */ +static int tsl2772_invoke_change(struct iio_dev *indio_dev) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + int device_status = chip->tsl2772_chip_status; + int ret; + + mutex_lock(&chip->als_mutex); + mutex_lock(&chip->prox_mutex); + + if (device_status == TSL2772_CHIP_WORKING) { + ret = tsl2772_chip_off(indio_dev); + if (ret < 0) + goto unlock; + } + + ret = tsl2772_chip_on(indio_dev); + +unlock: + mutex_unlock(&chip->prox_mutex); + mutex_unlock(&chip->als_mutex); + + return ret; +} + +static int tsl2772_prox_cal(struct iio_dev *indio_dev) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + int prox_history[MAX_SAMPLES_CAL + 1]; + int i, ret, mean, max, sample_sum; + + if (chip->settings.prox_max_samples_cal < 1 || + chip->settings.prox_max_samples_cal > MAX_SAMPLES_CAL) + return -EINVAL; + + for (i = 0; i < chip->settings.prox_max_samples_cal; i++) { + usleep_range(15000, 17500); + ret = tsl2772_get_prox(indio_dev); + if (ret < 0) + return ret; + + prox_history[i] = chip->prox_data; + } + + sample_sum = 0; + max = INT_MIN; + for (i = 0; i < chip->settings.prox_max_samples_cal; i++) { + sample_sum += prox_history[i]; + max = max(max, prox_history[i]); + } + mean = sample_sum / chip->settings.prox_max_samples_cal; + + chip->settings.prox_thres_high = (max << 1) - mean; + + return tsl2772_invoke_change(indio_dev); +} + +static int tsl2772_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + if (chan->type == IIO_INTENSITY) { + *length = ARRAY_SIZE(tsl2772_int_calibscale_avail); + *vals = tsl2772_int_calibscale_avail; + } else { + *length = ARRAY_SIZE(tsl2772_prox_calibscale_avail); + *vals = tsl2772_prox_calibscale_avail; + } + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_INT_TIME: + *length = ARRAY_SIZE(tsl2772_int_time_avail[chip->id]); + *vals = tsl2772_int_time_avail[chip->id]; + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_RANGE; + } + + return -EINVAL; +} + +static ssize_t in_illuminance0_target_input_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsl2772_chip *chip = iio_priv(dev_to_iio_dev(dev)); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->settings.als_cal_target); +} + +static ssize_t in_illuminance0_target_input_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2772_chip *chip = iio_priv(indio_dev); + u16 value; + int ret; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + chip->settings.als_cal_target = value; + ret = tsl2772_invoke_change(indio_dev); + if (ret < 0) + return ret; + + return len; +} + +static ssize_t in_illuminance0_calibrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + bool value; + int ret; + + if (kstrtobool(buf, &value) || !value) + return -EINVAL; + + ret = tsl2772_als_calibrate(indio_dev); + if (ret < 0) + return ret; + + ret = tsl2772_invoke_change(indio_dev); + if (ret < 0) + return ret; + + return len; +} + +static ssize_t in_illuminance0_lux_table_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsl2772_chip *chip = iio_priv(dev_to_iio_dev(dev)); + int i = 0; + int offset = 0; + + while (i < TSL2772_MAX_LUX_TABLE_SIZE) { + offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,", + chip->tsl2772_device_lux[i].ch0, + chip->tsl2772_device_lux[i].ch1); + if (chip->tsl2772_device_lux[i].ch0 == 0) { + /* + * We just printed the first "0" entry. + * Now get rid of the extra "," and break. + */ + offset--; + break; + } + i++; + } + + offset += snprintf(buf + offset, PAGE_SIZE, "\n"); + return offset; +} + +static ssize_t in_illuminance0_lux_table_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct tsl2772_chip *chip = iio_priv(indio_dev); + int value[ARRAY_SIZE(chip->tsl2772_device_lux) * 2 + 1]; + int n, ret; + + 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 two ints to be one table entry, + * and the last table entry is all 0. + */ + n = value[0]; + if ((n % 2) || n < 4 || + n > ((ARRAY_SIZE(chip->tsl2772_device_lux) - 1) * 2)) + return -EINVAL; + + if ((value[(n - 1)] | value[n]) != 0) + return -EINVAL; + + if (chip->tsl2772_chip_status == TSL2772_CHIP_WORKING) { + ret = tsl2772_chip_off(indio_dev); + if (ret < 0) + return ret; + } + + /* Zero out the table */ + memset(chip->tsl2772_device_lux, 0, sizeof(chip->tsl2772_device_lux)); + memcpy(chip->tsl2772_device_lux, &value[1], (value[0] * 4)); + + ret = tsl2772_invoke_change(indio_dev); + if (ret < 0) + return ret; + + return len; +} + +static ssize_t in_proximity0_calibrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + bool value; + int ret; + + if (kstrtobool(buf, &value) || !value) + return -EINVAL; + + ret = tsl2772_prox_cal(indio_dev); + if (ret < 0) + return ret; + + ret = tsl2772_invoke_change(indio_dev); + if (ret < 0) + return ret; + + return len; +} + +static int tsl2772_read_interrupt_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + + if (chan->type == IIO_INTENSITY) + return chip->settings.als_interrupt_en; + else + return chip->settings.prox_interrupt_en; +} + +static int tsl2772_write_interrupt_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int val) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + + if (chan->type == IIO_INTENSITY) + chip->settings.als_interrupt_en = val ? true : false; + else + chip->settings.prox_interrupt_en = val ? true : false; + + return tsl2772_invoke_change(indio_dev); +} + +static int tsl2772_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + int ret = -EINVAL, count, persistence; + u8 time; + + switch (info) { + case IIO_EV_INFO_VALUE: + if (chan->type == IIO_INTENSITY) { + switch (dir) { + case IIO_EV_DIR_RISING: + chip->settings.als_thresh_high = val; + ret = 0; + break; + case IIO_EV_DIR_FALLING: + chip->settings.als_thresh_low = val; + ret = 0; + break; + default: + break; + } + } else { + switch (dir) { + case IIO_EV_DIR_RISING: + chip->settings.prox_thres_high = val; + ret = 0; + break; + case IIO_EV_DIR_FALLING: + chip->settings.prox_thres_low = val; + ret = 0; + break; + default: + break; + } + } + break; + case IIO_EV_INFO_PERIOD: + if (chan->type == IIO_INTENSITY) + time = chip->settings.als_time; + else + time = chip->settings.prox_time; + + count = 256 - time; + persistence = ((val * 1000000) + val2) / + (count * tsl2772_int_time_avail[chip->id][3]); + + if (chan->type == IIO_INTENSITY) { + /* ALS filter values are 1, 2, 3, 5, 10, 15, ..., 60 */ + if (persistence > 3) + persistence = (persistence / 5) + 3; + + chip->settings.als_persistence = persistence; + } else { + chip->settings.prox_persistence = persistence; + } + + ret = 0; + break; + default: + break; + } + + if (ret < 0) + return ret; + + return tsl2772_invoke_change(indio_dev); +} + +static int tsl2772_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + int filter_delay, persistence; + u8 time; + + switch (info) { + case IIO_EV_INFO_VALUE: + if (chan->type == IIO_INTENSITY) { + switch (dir) { + case IIO_EV_DIR_RISING: + *val = chip->settings.als_thresh_high; + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + *val = chip->settings.als_thresh_low; + return IIO_VAL_INT; + default: + return -EINVAL; + } + } else { + switch (dir) { + case IIO_EV_DIR_RISING: + *val = chip->settings.prox_thres_high; + return IIO_VAL_INT; + case IIO_EV_DIR_FALLING: + *val = chip->settings.prox_thres_low; + return IIO_VAL_INT; + default: + return -EINVAL; + } + } + break; + case IIO_EV_INFO_PERIOD: + if (chan->type == IIO_INTENSITY) { + time = chip->settings.als_time; + persistence = chip->settings.als_persistence; + + /* ALS filter values are 1, 2, 3, 5, 10, 15, ..., 60 */ + if (persistence > 3) + persistence = (persistence - 3) * 5; + } else { + time = chip->settings.prox_time; + persistence = chip->settings.prox_persistence; + } + + filter_delay = persistence * (256 - time) * + tsl2772_int_time_avail[chip->id][3]; + + *val = filter_delay / 1000000; + *val2 = filter_delay % 1000000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int tsl2772_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, + int *val2, + long mask) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_LIGHT: + tsl2772_get_lux(indio_dev); + *val = chip->als_cur_info.lux; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_INTENSITY: + tsl2772_get_lux(indio_dev); + if (chan->channel == 0) + *val = chip->als_cur_info.als_ch0; + else + *val = chip->als_cur_info.als_ch1; + return IIO_VAL_INT; + case IIO_PROXIMITY: + tsl2772_get_prox(indio_dev); + *val = chip->prox_data; + return IIO_VAL_INT; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_CALIBSCALE: + if (chan->type == IIO_LIGHT) + *val = tsl2772_als_gain[chip->settings.als_gain]; + else + *val = tsl2772_prox_gain[chip->settings.prox_gain]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_CALIBBIAS: + *val = chip->settings.als_gain_trim; + return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + *val2 = (256 - chip->settings.als_time) * + tsl2772_int_time_avail[chip->id][3]; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int tsl2772_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct tsl2772_chip *chip = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_CALIBSCALE: + if (chan->type == IIO_INTENSITY) { + switch (val) { + case 1: + chip->settings.als_gain = 0; + break; + case 8: + chip->settings.als_gain = 1; + break; + case 16: + chip->settings.als_gain = 2; + break; + case 120: + chip->settings.als_gain = 3; + break; + default: + return -EINVAL; + } + } else { + switch (val) { + case 1: + chip->settings.prox_gain = 0; + break; + case 2: + chip->settings.prox_gain = 1; + break; + case 4: + chip->settings.prox_gain = 2; + break; + case 8: + chip->settings.prox_gain = 3; + break; + default: + return -EINVAL; + } + } + break; + case IIO_CHAN_INFO_CALIBBIAS: + if (val < TSL2772_ALS_GAIN_TRIM_MIN || + val > TSL2772_ALS_GAIN_TRIM_MAX) + return -EINVAL; + + chip->settings.als_gain_trim = val; + break; + case IIO_CHAN_INFO_INT_TIME: + if (val != 0 || val2 < tsl2772_int_time_avail[chip->id][1] || + val2 > tsl2772_int_time_avail[chip->id][5]) + return -EINVAL; + + chip->settings.als_time = 256 - + (val2 / tsl2772_int_time_avail[chip->id][3]); + break; + default: + return -EINVAL; + } + + return tsl2772_invoke_change(indio_dev); +} + +static DEVICE_ATTR_RW(in_illuminance0_target_input); + +static DEVICE_ATTR_WO(in_illuminance0_calibrate); + +static DEVICE_ATTR_WO(in_proximity0_calibrate); + +static DEVICE_ATTR_RW(in_illuminance0_lux_table); + +/* Use the default register values to identify the Taos device */ +static int tsl2772_device_id_verif(int id, int target) +{ + switch (target) { + case tsl2571: + case tsl2671: + case tsl2771: + return (id & 0xf0) == TRITON_ID; + case tmd2671: + case tmd2771: + return (id & 0xf0) == HALIBUT_ID; + case tsl2572: + case tsl2672: + case tmd2672: + case tsl2772: + case tmd2772: + return (id & 0xf0) == SWORDFISH_ID; + } + + return -EINVAL; +} + +static irqreturn_t tsl2772_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct tsl2772_chip *chip = iio_priv(indio_dev); + s64 timestamp = iio_get_time_ns(indio_dev); + int ret; + + ret = tsl2772_read_status(chip); + if (ret < 0) + return IRQ_HANDLED; + + /* What type of interrupt do we need to process */ + if (ret & TSL2772_STA_PRX_INTR) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + } + + if (ret & TSL2772_STA_ALS_INTR) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, + 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + } + + ret = i2c_smbus_write_byte(chip->client, + TSL2772_CMD_REG | TSL2772_CMD_SPL_FN | + TSL2772_CMD_PROXALS_INT_CLR); + if (ret < 0) + dev_err(&chip->client->dev, + "%s: failed to clear interrupt status: %d\n", + __func__, ret); + + return IRQ_HANDLED; +} + +static struct attribute *tsl2772_ALS_device_attrs[] = { + &dev_attr_in_illuminance0_target_input.attr, + &dev_attr_in_illuminance0_calibrate.attr, + &dev_attr_in_illuminance0_lux_table.attr, + NULL +}; + +static struct attribute *tsl2772_PRX_device_attrs[] = { + &dev_attr_in_proximity0_calibrate.attr, + NULL +}; + +static struct attribute *tsl2772_ALSPRX_device_attrs[] = { + &dev_attr_in_illuminance0_target_input.attr, + &dev_attr_in_illuminance0_calibrate.attr, + &dev_attr_in_illuminance0_lux_table.attr, + NULL +}; + +static struct attribute *tsl2772_PRX2_device_attrs[] = { + &dev_attr_in_proximity0_calibrate.attr, + NULL +}; + +static struct attribute *tsl2772_ALSPRX2_device_attrs[] = { + &dev_attr_in_illuminance0_target_input.attr, + &dev_attr_in_illuminance0_calibrate.attr, + &dev_attr_in_illuminance0_lux_table.attr, + &dev_attr_in_proximity0_calibrate.attr, + NULL +}; + +static const struct attribute_group tsl2772_device_attr_group_tbl[] = { + [ALS] = { + .attrs = tsl2772_ALS_device_attrs, + }, + [PRX] = { + .attrs = tsl2772_PRX_device_attrs, + }, + [ALSPRX] = { + .attrs = tsl2772_ALSPRX_device_attrs, + }, + [PRX2] = { + .attrs = tsl2772_PRX2_device_attrs, + }, + [ALSPRX2] = { + .attrs = tsl2772_ALSPRX2_device_attrs, + }, +}; + +#define TSL2772_DEVICE_INFO(type)[type] = \ + { \ + .attrs = &tsl2772_device_attr_group_tbl[type], \ + .read_raw = &tsl2772_read_raw, \ + .read_avail = &tsl2772_read_avail, \ + .write_raw = &tsl2772_write_raw, \ + .read_event_value = &tsl2772_read_event_value, \ + .write_event_value = &tsl2772_write_event_value, \ + .read_event_config = &tsl2772_read_interrupt_config, \ + .write_event_config = &tsl2772_write_interrupt_config, \ + } + +static const struct iio_info tsl2772_device_info[] = { + TSL2772_DEVICE_INFO(ALS), + TSL2772_DEVICE_INFO(PRX), + TSL2772_DEVICE_INFO(ALSPRX), + TSL2772_DEVICE_INFO(PRX2), + TSL2772_DEVICE_INFO(ALSPRX2), +}; + +static const struct iio_event_spec tsl2772_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_PERIOD) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct tsl2772_chip_info tsl2772_chip_info_tbl[] = { + [ALS] = { + .channel_with_events = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .event_spec = tsl2772_events, + .num_event_specs = ARRAY_SIZE(tsl2772_events), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + }, + }, + .channel_without_events = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + }, + }, + .chan_table_elements = 3, + .info = &tsl2772_device_info[ALS], + }, + [PRX] = { + .channel_with_events = { + { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .event_spec = tsl2772_events, + .num_event_specs = ARRAY_SIZE(tsl2772_events), + }, + }, + .channel_without_events = { + { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, + }, + .chan_table_elements = 1, + .info = &tsl2772_device_info[PRX], + }, + [ALSPRX] = { + .channel_with_events = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .event_spec = tsl2772_events, + .num_event_specs = ARRAY_SIZE(tsl2772_events), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .event_spec = tsl2772_events, + .num_event_specs = ARRAY_SIZE(tsl2772_events), + }, + }, + .channel_without_events = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, + }, + .chan_table_elements = 4, + .info = &tsl2772_device_info[ALSPRX], + }, + [PRX2] = { + .channel_with_events = { + { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_CALIBSCALE), + .event_spec = tsl2772_events, + .num_event_specs = ARRAY_SIZE(tsl2772_events), + }, + }, + .channel_without_events = { + { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_CALIBSCALE), + }, + }, + .chan_table_elements = 1, + .info = &tsl2772_device_info[PRX2], + }, + [ALSPRX2] = { + .channel_with_events = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .event_spec = tsl2772_events, + .num_event_specs = ARRAY_SIZE(tsl2772_events), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_CALIBSCALE), + .event_spec = tsl2772_events, + .num_event_specs = ARRAY_SIZE(tsl2772_events), + }, + }, + .channel_without_events = { + { + .type = IIO_LIGHT, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE) | + BIT(IIO_CHAN_INFO_CALIBBIAS), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_INT_TIME) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + }, { + .type = IIO_INTENSITY, + .indexed = 1, + .channel = 1, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + }, { + .type = IIO_PROXIMITY, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + .info_mask_separate_available = + BIT(IIO_CHAN_INFO_CALIBSCALE), + }, + }, + .chan_table_elements = 4, + .info = &tsl2772_device_info[ALSPRX2], + }, +}; + +static int tsl2772_probe(struct i2c_client *clientp, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct tsl2772_chip *chip; + int ret; + + indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + + chip = iio_priv(indio_dev); + chip->client = clientp; + i2c_set_clientdata(clientp, indio_dev); + + ret = i2c_smbus_read_byte_data(chip->client, + TSL2772_CMD_REG | TSL2772_CHIPID); + if (ret < 0) + return ret; + + if (tsl2772_device_id_verif(ret, id->driver_data) <= 0) { + dev_info(&chip->client->dev, + "%s: i2c device found does not match expected id\n", + __func__); + return -EINVAL; + } + + ret = i2c_smbus_write_byte(clientp, TSL2772_CMD_REG | TSL2772_CNTRL); + if (ret < 0) { + dev_err(&clientp->dev, + "%s: Failed to write to CMD register: %d\n", + __func__, ret); + return ret; + } + + mutex_init(&chip->als_mutex); + mutex_init(&chip->prox_mutex); + + chip->tsl2772_chip_status = TSL2772_CHIP_UNKNOWN; + chip->pdata = dev_get_platdata(&clientp->dev); + chip->id = id->driver_data; + chip->chip_info = + &tsl2772_chip_info_tbl[device_channel_config[id->driver_data]]; + + indio_dev->info = chip->chip_info->info; + indio_dev->dev.parent = &clientp->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = chip->client->name; + indio_dev->num_channels = chip->chip_info->chan_table_elements; + + if (clientp->irq) { + indio_dev->channels = chip->chip_info->channel_with_events; + + ret = devm_request_threaded_irq(&clientp->dev, clientp->irq, + NULL, + &tsl2772_event_handler, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "TSL2772_event", + indio_dev); + if (ret) { + dev_err(&clientp->dev, + "%s: irq request failed\n", __func__); + return ret; + } + } else { + indio_dev->channels = chip->chip_info->channel_without_events; + } + + tsl2772_defaults(chip); + ret = tsl2772_chip_on(indio_dev); + if (ret < 0) + return ret; + + ret = iio_device_register(indio_dev); + if (ret) { + tsl2772_chip_off(indio_dev); + dev_err(&clientp->dev, + "%s: iio registration failed\n", __func__); + return ret; + } + + return 0; +} + +static int tsl2772_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return tsl2772_chip_off(indio_dev); +} + +static int tsl2772_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return tsl2772_chip_on(indio_dev); +} + +static int tsl2772_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + tsl2772_chip_off(indio_dev); + + iio_device_unregister(indio_dev); + + return 0; +} + +static const struct i2c_device_id tsl2772_idtable[] = { + { "tsl2571", tsl2571 }, + { "tsl2671", tsl2671 }, + { "tmd2671", tmd2671 }, + { "tsl2771", tsl2771 }, + { "tmd2771", tmd2771 }, + { "tsl2572", tsl2572 }, + { "tsl2672", tsl2672 }, + { "tmd2672", tmd2672 }, + { "tsl2772", tsl2772 }, + { "tmd2772", tmd2772 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, tsl2772_idtable); + +static const struct of_device_id tsl2772_of_match[] = { + { .compatible = "amstaos,tsl2571" }, + { .compatible = "amstaos,tsl2671" }, + { .compatible = "amstaos,tmd2671" }, + { .compatible = "amstaos,tsl2771" }, + { .compatible = "amstaos,tmd2771" }, + { .compatible = "amstaos,tsl2572" }, + { .compatible = "amstaos,tsl2672" }, + { .compatible = "amstaos,tmd2672" }, + { .compatible = "amstaos,tsl2772" }, + { .compatible = "amstaos,tmd2772" }, + {} +}; +MODULE_DEVICE_TABLE(of, tsl2772_of_match); + +static const struct dev_pm_ops tsl2772_pm_ops = { + .suspend = tsl2772_suspend, + .resume = tsl2772_resume, +}; + +static struct i2c_driver tsl2772_driver = { + .driver = { + .name = "tsl2772", + .of_match_table = tsl2772_of_match, + .pm = &tsl2772_pm_ops, + }, + .id_table = tsl2772_idtable, + .probe = tsl2772_probe, + .remove = tsl2772_remove, +}; + +module_i2c_driver(tsl2772_driver); + +MODULE_AUTHOR("J. August Brenner "); +MODULE_AUTHOR("Brian Masney "); +MODULE_DESCRIPTION("TAOS tsl2772 ambient and proximity light sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index bd9445956511..aee2335a25a1 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -11,7 +11,6 @@ source "drivers/staging/iio/cdc/Kconfig" source "drivers/staging/iio/frequency/Kconfig" source "drivers/staging/iio/gyro/Kconfig" source "drivers/staging/iio/impedance-analyzer/Kconfig" -source "drivers/staging/iio/light/Kconfig" source "drivers/staging/iio/meter/Kconfig" source "drivers/staging/iio/resolver/Kconfig" diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile index e99a375c07b9..c28d657497de 100644 --- a/drivers/staging/iio/Makefile +++ b/drivers/staging/iio/Makefile @@ -10,6 +10,5 @@ obj-y += cdc/ obj-y += frequency/ obj-y += gyro/ obj-y += impedance-analyzer/ -obj-y += light/ obj-y += meter/ obj-y += resolver/ diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig deleted file mode 100644 index dfa37386ad2c..000000000000 --- a/drivers/staging/iio/light/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# -# Light sensors -# -menu "Light sensors" - -config TSL2772 - tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors" - depends on I2C - help - Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672, - tmd2672, tsl2772, tmd2772 devices. - Provides iio_events and direct access via sysfs. - -endmenu diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile deleted file mode 100644 index e7e77a11f02a..000000000000 --- a/drivers/staging/iio/light/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for industrial I/O Light sensors -# - -obj-$(CONFIG_TSL2772) += tsl2772.o diff --git a/drivers/staging/iio/light/tsl2772.c b/drivers/staging/iio/light/tsl2772.c deleted file mode 100644 index a59bf39c28d4..000000000000 --- a/drivers/staging/iio/light/tsl2772.c +++ /dev/null @@ -1,1800 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Device driver for monitoring ambient light intensity in (lux) and proximity - * detection (prox) within the TAOS TSL2571, TSL2671, TMD2671, TSL2771, TMD2771, - * TSL2572, TSL2672, TMD2672, TSL2772, and TMD2772 devices. - * - * Copyright (c) 2012, TAOS Corporation. - * Copyright (c) 2017-2018 Brian Masney - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tsl2772.h" - -/* Cal defs */ -#define PROX_STAT_CAL 0 -#define PROX_STAT_SAMP 1 -#define MAX_SAMPLES_CAL 200 - -/* TSL2772 Device ID */ -#define TRITON_ID 0x00 -#define SWORDFISH_ID 0x30 -#define HALIBUT_ID 0x20 - -/* Lux calculation constants */ -#define TSL2772_LUX_CALC_OVER_FLOW 65535 - -/* - * TAOS Register definitions - Note: depending on device, some of these register - * are not used and the register address is benign. - */ - -/* Register offsets */ -#define TSL2772_MAX_CONFIG_REG 16 - -/* Device Registers and Masks */ -#define TSL2772_CNTRL 0x00 -#define TSL2772_ALS_TIME 0X01 -#define TSL2772_PRX_TIME 0x02 -#define TSL2772_WAIT_TIME 0x03 -#define TSL2772_ALS_MINTHRESHLO 0X04 -#define TSL2772_ALS_MINTHRESHHI 0X05 -#define TSL2772_ALS_MAXTHRESHLO 0X06 -#define TSL2772_ALS_MAXTHRESHHI 0X07 -#define TSL2772_PRX_MINTHRESHLO 0X08 -#define TSL2772_PRX_MINTHRESHHI 0X09 -#define TSL2772_PRX_MAXTHRESHLO 0X0A -#define TSL2772_PRX_MAXTHRESHHI 0X0B -#define TSL2772_PERSISTENCE 0x0C -#define TSL2772_ALS_PRX_CONFIG 0x0D -#define TSL2772_PRX_COUNT 0x0E -#define TSL2772_GAIN 0x0F -#define TSL2772_NOTUSED 0x10 -#define TSL2772_REVID 0x11 -#define TSL2772_CHIPID 0x12 -#define TSL2772_STATUS 0x13 -#define TSL2772_ALS_CHAN0LO 0x14 -#define TSL2772_ALS_CHAN0HI 0x15 -#define TSL2772_ALS_CHAN1LO 0x16 -#define TSL2772_ALS_CHAN1HI 0x17 -#define TSL2772_PRX_LO 0x18 -#define TSL2772_PRX_HI 0x19 - -/* tsl2772 cmd reg masks */ -#define TSL2772_CMD_REG 0x80 -#define TSL2772_CMD_SPL_FN 0x60 -#define TSL2772_CMD_REPEAT_PROTO 0x00 -#define TSL2772_CMD_AUTOINC_PROTO 0x20 - -#define TSL2772_CMD_PROX_INT_CLR 0X05 -#define TSL2772_CMD_ALS_INT_CLR 0x06 -#define TSL2772_CMD_PROXALS_INT_CLR 0X07 - -/* tsl2772 cntrl reg masks */ -#define TSL2772_CNTL_ADC_ENBL 0x02 -#define TSL2772_CNTL_PWR_ON 0x01 - -/* tsl2772 status reg masks */ -#define TSL2772_STA_ADC_VALID 0x01 -#define TSL2772_STA_PRX_VALID 0x02 -#define TSL2772_STA_ADC_PRX_VALID (TSL2772_STA_ADC_VALID | \ - TSL2772_STA_PRX_VALID) -#define TSL2772_STA_ALS_INTR 0x10 -#define TSL2772_STA_PRX_INTR 0x20 - -/* tsl2772 cntrl reg masks */ -#define TSL2772_CNTL_REG_CLEAR 0x00 -#define TSL2772_CNTL_PROX_INT_ENBL 0X20 -#define TSL2772_CNTL_ALS_INT_ENBL 0X10 -#define TSL2772_CNTL_WAIT_TMR_ENBL 0X08 -#define TSL2772_CNTL_PROX_DET_ENBL 0X04 -#define TSL2772_CNTL_PWRON 0x01 -#define TSL2772_CNTL_ALSPON_ENBL 0x03 -#define TSL2772_CNTL_INTALSPON_ENBL 0x13 -#define TSL2772_CNTL_PROXPON_ENBL 0x0F -#define TSL2772_CNTL_INTPROXPON_ENBL 0x2F - -#define TSL2772_ALS_GAIN_TRIM_MIN 250 -#define TSL2772_ALS_GAIN_TRIM_MAX 4000 - -/* Device family members */ -enum { - tsl2571, - tsl2671, - tmd2671, - tsl2771, - tmd2771, - tsl2572, - tsl2672, - tmd2672, - tsl2772, - tmd2772 -}; - -enum { - TSL2772_CHIP_UNKNOWN = 0, - TSL2772_CHIP_WORKING = 1, - TSL2772_CHIP_SUSPENDED = 2 -}; - -/* Per-device data */ -struct tsl2772_als_info { - u16 als_ch0; - u16 als_ch1; - u16 lux; -}; - -struct tsl2772_chip_info { - int chan_table_elements; - struct iio_chan_spec channel_with_events[4]; - struct iio_chan_spec channel_without_events[4]; - const struct iio_info *info; -}; - -struct tsl2772_chip { - kernel_ulong_t id; - struct mutex prox_mutex; - struct mutex als_mutex; - struct i2c_client *client; - u16 prox_data; - struct tsl2772_als_info als_cur_info; - struct tsl2772_settings settings; - struct tsl2772_platform_data *pdata; - int als_gain_time_scale; - int als_saturation; - int tsl2772_chip_status; - u8 tsl2772_config[TSL2772_MAX_CONFIG_REG]; - const struct tsl2772_chip_info *chip_info; - const struct iio_info *info; - s64 event_timestamp; - /* - * This structure is intentionally large to accommodate - * updates via sysfs. - * Sized to 9 = max 8 segments + 1 termination segment - */ - struct tsl2772_lux tsl2772_device_lux[TSL2772_MAX_LUX_TABLE_SIZE]; -}; - -/* - * Different devices require different coefficents, and these numbers were - * derived from the 'Lux Equation' section of the various device datasheets. - * All of these coefficients assume a Glass Attenuation (GA) factor of 1. - * The coefficients are multiplied by 1000 to avoid floating point operations. - * The two rows in each table correspond to the Lux1 and Lux2 equations from - * the datasheets. - */ -static const struct tsl2772_lux tsl2x71_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { - { 53000, 106000 }, - { 31800, 53000 }, - { 0, 0 }, -}; - -static const struct tsl2772_lux tmd2x71_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { - { 24000, 48000 }, - { 14400, 24000 }, - { 0, 0 }, -}; - -static const struct tsl2772_lux tsl2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { - { 60000, 112200 }, - { 37800, 60000 }, - { 0, 0 }, -}; - -static const struct tsl2772_lux tmd2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = { - { 20000, 35000 }, - { 12600, 20000 }, - { 0, 0 }, -}; - -static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = { - [tsl2571] = tsl2x71_lux_table, - [tsl2671] = tsl2x71_lux_table, - [tmd2671] = tmd2x71_lux_table, - [tsl2771] = tsl2x71_lux_table, - [tmd2771] = tmd2x71_lux_table, - [tsl2572] = tsl2x72_lux_table, - [tsl2672] = tsl2x72_lux_table, - [tmd2672] = tmd2x72_lux_table, - [tsl2772] = tsl2x72_lux_table, - [tmd2772] = tmd2x72_lux_table, -}; - -static const struct tsl2772_settings tsl2772_default_settings = { - .als_time = 255, /* 2.72 / 2.73 ms */ - .als_gain = 0, - .prox_time = 255, /* 2.72 / 2.73 ms */ - .prox_gain = 0, - .wait_time = 255, - .als_prox_config = 0, - .als_gain_trim = 1000, - .als_cal_target = 150, - .als_persistence = 1, - .als_interrupt_en = false, - .als_thresh_low = 200, - .als_thresh_high = 256, - .prox_persistence = 1, - .prox_interrupt_en = false, - .prox_thres_low = 0, - .prox_thres_high = 512, - .prox_max_samples_cal = 30, - .prox_pulse_count = 8, - .prox_diode = TSL2772_DIODE1, - .prox_power = TSL2772_100_mA -}; - -static const s16 tsl2772_als_gain[] = { - 1, - 8, - 16, - 120 -}; - -static const s16 tsl2772_prox_gain[] = { - 1, - 2, - 4, - 8 -}; - -static const int tsl2772_int_time_avail[][6] = { - [tsl2571] = { 0, 2720, 0, 2720, 0, 696000 }, - [tsl2671] = { 0, 2720, 0, 2720, 0, 696000 }, - [tmd2671] = { 0, 2720, 0, 2720, 0, 696000 }, - [tsl2771] = { 0, 2720, 0, 2720, 0, 696000 }, - [tmd2771] = { 0, 2720, 0, 2720, 0, 696000 }, - [tsl2572] = { 0, 2730, 0, 2730, 0, 699000 }, - [tsl2672] = { 0, 2730, 0, 2730, 0, 699000 }, - [tmd2672] = { 0, 2730, 0, 2730, 0, 699000 }, - [tsl2772] = { 0, 2730, 0, 2730, 0, 699000 }, - [tmd2772] = { 0, 2730, 0, 2730, 0, 699000 }, -}; - -static int tsl2772_int_calibscale_avail[] = { 1, 8, 16, 120 }; - -static int tsl2772_prox_calibscale_avail[] = { 1, 2, 4, 8 }; - -/* Channel variations */ -enum { - ALS, - PRX, - ALSPRX, - PRX2, - ALSPRX2, -}; - -static const u8 device_channel_config[] = { - [tsl2571] = ALS, - [tsl2671] = PRX, - [tmd2671] = PRX, - [tsl2771] = ALSPRX, - [tmd2771] = ALSPRX, - [tsl2572] = ALS, - [tsl2672] = PRX2, - [tmd2672] = PRX2, - [tsl2772] = ALSPRX2, - [tmd2772] = ALSPRX2 -}; - -static int tsl2772_read_status(struct tsl2772_chip *chip) -{ - int ret; - - ret = i2c_smbus_read_byte_data(chip->client, - TSL2772_CMD_REG | TSL2772_STATUS); - if (ret < 0) - dev_err(&chip->client->dev, - "%s: failed to read STATUS register: %d\n", __func__, - ret); - - return ret; -} - -static int tsl2772_write_control_reg(struct tsl2772_chip *chip, u8 data) -{ - int ret; - - ret = i2c_smbus_write_byte_data(chip->client, - TSL2772_CMD_REG | TSL2772_CNTRL, data); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed to write to control register %x: %d\n", - __func__, data, ret); - } - - return ret; -} - -static int tsl2772_read_autoinc_regs(struct tsl2772_chip *chip, int lower_reg, - int upper_reg) -{ - u8 buf[2]; - int ret; - - ret = i2c_smbus_write_byte(chip->client, - TSL2772_CMD_REG | TSL2772_CMD_AUTOINC_PROTO | - lower_reg); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed to enable auto increment protocol: %d\n", - __func__, ret); - return ret; - } - - ret = i2c_smbus_read_byte_data(chip->client, - TSL2772_CMD_REG | lower_reg); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed to read from register %x: %d\n", __func__, - lower_reg, ret); - return ret; - } - buf[0] = ret; - - ret = i2c_smbus_read_byte_data(chip->client, - TSL2772_CMD_REG | upper_reg); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed to read from register %x: %d\n", __func__, - upper_reg, ret); - return ret; - } - buf[1] = ret; - - ret = i2c_smbus_write_byte(chip->client, - TSL2772_CMD_REG | TSL2772_CMD_REPEAT_PROTO | - lower_reg); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed to enable repeated byte protocol: %d\n", - __func__, ret); - return ret; - } - - return le16_to_cpup((const __le16 *)&buf[0]); -} - -/** - * tsl2772_get_lux() - Reads and calculates current lux value. - * @indio_dev: pointer to IIO device - * - * The raw ch0 and ch1 values of the ambient light sensed in the last - * integration cycle are read from the device. The raw values are multiplied - * by a device-specific scale factor, and divided by the integration time and - * device gain. The code supports multiple lux equations through the lux table - * coefficients. A lux gain trim is applied to each lux equation, and then the - * maximum lux within the interval 0..65535 is selected. - */ -static int tsl2772_get_lux(struct iio_dev *indio_dev) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - struct tsl2772_lux *p; - int max_lux, ret; - bool overflow; - - mutex_lock(&chip->als_mutex); - - if (chip->tsl2772_chip_status != TSL2772_CHIP_WORKING) { - dev_err(&chip->client->dev, "%s: device is not enabled\n", - __func__); - ret = -EBUSY; - goto out_unlock; - } - - ret = tsl2772_read_status(chip); - if (ret < 0) - goto out_unlock; - - if (!(ret & TSL2772_STA_ADC_VALID)) { - dev_err(&chip->client->dev, - "%s: data not valid yet\n", __func__); - ret = chip->als_cur_info.lux; /* return LAST VALUE */ - goto out_unlock; - } - - ret = tsl2772_read_autoinc_regs(chip, TSL2772_ALS_CHAN0LO, - TSL2772_ALS_CHAN0HI); - if (ret < 0) - goto out_unlock; - chip->als_cur_info.als_ch0 = ret; - - ret = tsl2772_read_autoinc_regs(chip, TSL2772_ALS_CHAN1LO, - TSL2772_ALS_CHAN1HI); - if (ret < 0) - goto out_unlock; - chip->als_cur_info.als_ch1 = ret; - - if (chip->als_cur_info.als_ch0 >= chip->als_saturation) { - max_lux = TSL2772_LUX_CALC_OVER_FLOW; - goto update_struct_with_max_lux; - } - - if (!chip->als_cur_info.als_ch0) { - /* have no data, so return LAST VALUE */ - ret = chip->als_cur_info.lux; - goto out_unlock; - } - - max_lux = 0; - overflow = false; - for (p = (struct tsl2772_lux *)chip->tsl2772_device_lux; p->ch0 != 0; - p++) { - int lux; - - lux = ((chip->als_cur_info.als_ch0 * p->ch0) - - (chip->als_cur_info.als_ch1 * p->ch1)) / - chip->als_gain_time_scale; - - /* - * The als_gain_trim can have a value within the range 250..4000 - * and is a multiplier for the lux. A trim of 1000 makes no - * changes to the lux, less than 1000 scales it down, and - * greater than 1000 scales it up. - */ - lux = (lux * chip->settings.als_gain_trim) / 1000; - - if (lux > TSL2772_LUX_CALC_OVER_FLOW) { - overflow = true; - continue; - } - - max_lux = max(max_lux, lux); - } - - if (overflow && max_lux == 0) - max_lux = TSL2772_LUX_CALC_OVER_FLOW; - -update_struct_with_max_lux: - chip->als_cur_info.lux = max_lux; - ret = max_lux; - -out_unlock: - mutex_unlock(&chip->als_mutex); - - return ret; -} - -/** - * tsl2772_get_prox() - Reads proximity data registers and updates - * chip->prox_data. - * - * @indio_dev: pointer to IIO device - */ -static int tsl2772_get_prox(struct iio_dev *indio_dev) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - int ret; - - mutex_lock(&chip->prox_mutex); - - ret = tsl2772_read_status(chip); - if (ret < 0) - goto prox_poll_err; - - switch (chip->id) { - case tsl2571: - case tsl2671: - case tmd2671: - case tsl2771: - case tmd2771: - if (!(ret & TSL2772_STA_ADC_VALID)) { - ret = -EINVAL; - goto prox_poll_err; - } - break; - case tsl2572: - case tsl2672: - case tmd2672: - case tsl2772: - case tmd2772: - if (!(ret & TSL2772_STA_PRX_VALID)) { - ret = -EINVAL; - goto prox_poll_err; - } - break; - } - - ret = tsl2772_read_autoinc_regs(chip, TSL2772_PRX_LO, TSL2772_PRX_HI); - if (ret < 0) - goto prox_poll_err; - chip->prox_data = ret; - -prox_poll_err: - mutex_unlock(&chip->prox_mutex); - - return ret; -} - -/** - * tsl2772_defaults() - Populates the device nominal operating parameters - * with those provided by a 'platform' data struct or - * with prefined defaults. - * - * @chip: pointer to device structure. - */ -static void tsl2772_defaults(struct tsl2772_chip *chip) -{ - /* If Operational settings defined elsewhere.. */ - if (chip->pdata && chip->pdata->platform_default_settings) - memcpy(&chip->settings, chip->pdata->platform_default_settings, - sizeof(tsl2772_default_settings)); - else - memcpy(&chip->settings, &tsl2772_default_settings, - sizeof(tsl2772_default_settings)); - - /* Load up the proper lux table. */ - if (chip->pdata && chip->pdata->platform_lux_table[0].ch0 != 0) - memcpy(chip->tsl2772_device_lux, - chip->pdata->platform_lux_table, - sizeof(chip->pdata->platform_lux_table)); - else - memcpy(chip->tsl2772_device_lux, - tsl2772_default_lux_table_group[chip->id], - TSL2772_DEFAULT_TABLE_BYTES); -} - -/** - * tsl2772_als_calibrate() - Obtain single reading and calculate - * the als_gain_trim. - * - * @indio_dev: pointer to IIO device - */ -static int tsl2772_als_calibrate(struct iio_dev *indio_dev) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - int ret, lux_val; - - ret = i2c_smbus_read_byte_data(chip->client, - TSL2772_CMD_REG | TSL2772_CNTRL); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed to read from the CNTRL register\n", - __func__); - return ret; - } - - if ((ret & (TSL2772_CNTL_ADC_ENBL | TSL2772_CNTL_PWR_ON)) - != (TSL2772_CNTL_ADC_ENBL | TSL2772_CNTL_PWR_ON)) { - dev_err(&chip->client->dev, - "%s: Device is not powered on and/or ADC is not enabled\n", - __func__); - return -EINVAL; - } else if ((ret & TSL2772_STA_ADC_VALID) != TSL2772_STA_ADC_VALID) { - dev_err(&chip->client->dev, - "%s: The two ADC channels have not completed an integration cycle\n", - __func__); - return -ENODATA; - } - - lux_val = tsl2772_get_lux(indio_dev); - if (lux_val < 0) { - dev_err(&chip->client->dev, - "%s: failed to get lux\n", __func__); - return lux_val; - } - - ret = (chip->settings.als_cal_target * chip->settings.als_gain_trim) / - lux_val; - if (ret < TSL2772_ALS_GAIN_TRIM_MIN || ret > TSL2772_ALS_GAIN_TRIM_MAX) - return -ERANGE; - - chip->settings.als_gain_trim = ret; - - return ret; -} - -static int tsl2772_chip_on(struct iio_dev *indio_dev) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - int ret, i, als_count, als_time_us; - u8 *dev_reg, reg_val; - - /* Non calculated parameters */ - chip->tsl2772_config[TSL2772_ALS_TIME] = chip->settings.als_time; - chip->tsl2772_config[TSL2772_PRX_TIME] = chip->settings.prox_time; - chip->tsl2772_config[TSL2772_WAIT_TIME] = chip->settings.wait_time; - chip->tsl2772_config[TSL2772_ALS_PRX_CONFIG] = - chip->settings.als_prox_config; - - chip->tsl2772_config[TSL2772_ALS_MINTHRESHLO] = - (chip->settings.als_thresh_low) & 0xFF; - chip->tsl2772_config[TSL2772_ALS_MINTHRESHHI] = - (chip->settings.als_thresh_low >> 8) & 0xFF; - chip->tsl2772_config[TSL2772_ALS_MAXTHRESHLO] = - (chip->settings.als_thresh_high) & 0xFF; - chip->tsl2772_config[TSL2772_ALS_MAXTHRESHHI] = - (chip->settings.als_thresh_high >> 8) & 0xFF; - chip->tsl2772_config[TSL2772_PERSISTENCE] = - (chip->settings.prox_persistence & 0xFF) << 4 | - (chip->settings.als_persistence & 0xFF); - - chip->tsl2772_config[TSL2772_PRX_COUNT] = - chip->settings.prox_pulse_count; - chip->tsl2772_config[TSL2772_PRX_MINTHRESHLO] = - (chip->settings.prox_thres_low) & 0xFF; - chip->tsl2772_config[TSL2772_PRX_MINTHRESHHI] = - (chip->settings.prox_thres_low >> 8) & 0xFF; - chip->tsl2772_config[TSL2772_PRX_MAXTHRESHLO] = - (chip->settings.prox_thres_high) & 0xFF; - chip->tsl2772_config[TSL2772_PRX_MAXTHRESHHI] = - (chip->settings.prox_thres_high >> 8) & 0xFF; - - /* and make sure we're not already on */ - if (chip->tsl2772_chip_status == TSL2772_CHIP_WORKING) { - /* if forcing a register update - turn off, then on */ - dev_info(&chip->client->dev, "device is already enabled\n"); - return -EINVAL; - } - - /* Set the gain based on tsl2772_settings struct */ - chip->tsl2772_config[TSL2772_GAIN] = - (chip->settings.als_gain & 0xFF) | - ((chip->settings.prox_gain & 0xFF) << 2) | - (chip->settings.prox_diode << 4) | - (chip->settings.prox_power << 6); - - /* set chip time scaling and saturation */ - als_count = 256 - chip->settings.als_time; - als_time_us = als_count * tsl2772_int_time_avail[chip->id][3]; - chip->als_saturation = als_count * 768; /* 75% of full scale */ - chip->als_gain_time_scale = als_time_us * - tsl2772_als_gain[chip->settings.als_gain]; - - /* - * TSL2772 Specific power-on / adc enable sequence - * Power on the device 1st. - */ - ret = tsl2772_write_control_reg(chip, TSL2772_CNTL_PWR_ON); - if (ret < 0) - return ret; - - /* - * Use the following shadow copy for our delay before enabling ADC. - * Write all the registers. - */ - for (i = 0, dev_reg = chip->tsl2772_config; - i < TSL2772_MAX_CONFIG_REG; i++) { - int reg = TSL2772_CMD_REG + i; - - ret = i2c_smbus_write_byte_data(chip->client, reg, - *dev_reg++); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed to write to register %x: %d\n", - __func__, reg, ret); - return ret; - } - } - - /* Power-on settling time */ - usleep_range(3000, 3500); - - reg_val = TSL2772_CNTL_PWR_ON | TSL2772_CNTL_ADC_ENBL | - TSL2772_CNTL_PROX_DET_ENBL; - if (chip->settings.als_interrupt_en) - reg_val |= TSL2772_CNTL_ALS_INT_ENBL; - if (chip->settings.prox_interrupt_en) - reg_val |= TSL2772_CNTL_PROX_INT_ENBL; - - ret = tsl2772_write_control_reg(chip, reg_val); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte(chip->client, - TSL2772_CMD_REG | TSL2772_CMD_SPL_FN | - TSL2772_CMD_PROXALS_INT_CLR); - if (ret < 0) { - dev_err(&chip->client->dev, - "%s: failed to clear interrupt status: %d\n", - __func__, ret); - return ret; - } - - chip->tsl2772_chip_status = TSL2772_CHIP_WORKING; - - return ret; -} - -static int tsl2772_chip_off(struct iio_dev *indio_dev) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - - /* turn device off */ - chip->tsl2772_chip_status = TSL2772_CHIP_SUSPENDED; - return tsl2772_write_control_reg(chip, 0x00); -} - -/** - * tsl2772_invoke_change - power cycle the device to implement the user - * parameters - * @indio_dev: pointer to IIO device - * - * Obtain and lock both ALS and PROX resources, determine and save device state - * (On/Off), cycle device to implement updated parameter, put device back into - * proper state, and unlock resource. - */ -static int tsl2772_invoke_change(struct iio_dev *indio_dev) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - int device_status = chip->tsl2772_chip_status; - int ret; - - mutex_lock(&chip->als_mutex); - mutex_lock(&chip->prox_mutex); - - if (device_status == TSL2772_CHIP_WORKING) { - ret = tsl2772_chip_off(indio_dev); - if (ret < 0) - goto unlock; - } - - ret = tsl2772_chip_on(indio_dev); - -unlock: - mutex_unlock(&chip->prox_mutex); - mutex_unlock(&chip->als_mutex); - - return ret; -} - -static int tsl2772_prox_cal(struct iio_dev *indio_dev) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - int prox_history[MAX_SAMPLES_CAL + 1]; - int i, ret, mean, max, sample_sum; - - if (chip->settings.prox_max_samples_cal < 1 || - chip->settings.prox_max_samples_cal > MAX_SAMPLES_CAL) - return -EINVAL; - - for (i = 0; i < chip->settings.prox_max_samples_cal; i++) { - usleep_range(15000, 17500); - ret = tsl2772_get_prox(indio_dev); - if (ret < 0) - return ret; - - prox_history[i] = chip->prox_data; - } - - sample_sum = 0; - max = INT_MIN; - for (i = 0; i < chip->settings.prox_max_samples_cal; i++) { - sample_sum += prox_history[i]; - max = max(max, prox_history[i]); - } - mean = sample_sum / chip->settings.prox_max_samples_cal; - - chip->settings.prox_thres_high = (max << 1) - mean; - - return tsl2772_invoke_change(indio_dev); -} - -static int tsl2772_read_avail(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - const int **vals, int *type, int *length, - long mask) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_CALIBSCALE: - if (chan->type == IIO_INTENSITY) { - *length = ARRAY_SIZE(tsl2772_int_calibscale_avail); - *vals = tsl2772_int_calibscale_avail; - } else { - *length = ARRAY_SIZE(tsl2772_prox_calibscale_avail); - *vals = tsl2772_prox_calibscale_avail; - } - *type = IIO_VAL_INT; - return IIO_AVAIL_LIST; - case IIO_CHAN_INFO_INT_TIME: - *length = ARRAY_SIZE(tsl2772_int_time_avail[chip->id]); - *vals = tsl2772_int_time_avail[chip->id]; - *type = IIO_VAL_INT_PLUS_MICRO; - return IIO_AVAIL_RANGE; - } - - return -EINVAL; -} - -static ssize_t in_illuminance0_target_input_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2772_chip *chip = iio_priv(dev_to_iio_dev(dev)); - - return snprintf(buf, PAGE_SIZE, "%d\n", chip->settings.als_cal_target); -} - -static ssize_t in_illuminance0_target_input_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct tsl2772_chip *chip = iio_priv(indio_dev); - u16 value; - int ret; - - if (kstrtou16(buf, 0, &value)) - return -EINVAL; - - chip->settings.als_cal_target = value; - ret = tsl2772_invoke_change(indio_dev); - if (ret < 0) - return ret; - - return len; -} - -static ssize_t in_illuminance0_calibrate_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - bool value; - int ret; - - if (kstrtobool(buf, &value) || !value) - return -EINVAL; - - ret = tsl2772_als_calibrate(indio_dev); - if (ret < 0) - return ret; - - ret = tsl2772_invoke_change(indio_dev); - if (ret < 0) - return ret; - - return len; -} - -static ssize_t in_illuminance0_lux_table_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tsl2772_chip *chip = iio_priv(dev_to_iio_dev(dev)); - int i = 0; - int offset = 0; - - while (i < TSL2772_MAX_LUX_TABLE_SIZE) { - offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,", - chip->tsl2772_device_lux[i].ch0, - chip->tsl2772_device_lux[i].ch1); - if (chip->tsl2772_device_lux[i].ch0 == 0) { - /* - * We just printed the first "0" entry. - * Now get rid of the extra "," and break. - */ - offset--; - break; - } - i++; - } - - offset += snprintf(buf + offset, PAGE_SIZE, "\n"); - return offset; -} - -static ssize_t in_illuminance0_lux_table_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct tsl2772_chip *chip = iio_priv(indio_dev); - int value[ARRAY_SIZE(chip->tsl2772_device_lux) * 2 + 1]; - int n, ret; - - 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 two ints to be one table entry, - * and the last table entry is all 0. - */ - n = value[0]; - if ((n % 2) || n < 4 || - n > ((ARRAY_SIZE(chip->tsl2772_device_lux) - 1) * 2)) - return -EINVAL; - - if ((value[(n - 1)] | value[n]) != 0) - return -EINVAL; - - if (chip->tsl2772_chip_status == TSL2772_CHIP_WORKING) { - ret = tsl2772_chip_off(indio_dev); - if (ret < 0) - return ret; - } - - /* Zero out the table */ - memset(chip->tsl2772_device_lux, 0, sizeof(chip->tsl2772_device_lux)); - memcpy(chip->tsl2772_device_lux, &value[1], (value[0] * 4)); - - ret = tsl2772_invoke_change(indio_dev); - if (ret < 0) - return ret; - - return len; -} - -static ssize_t in_proximity0_calibrate_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - bool value; - int ret; - - if (kstrtobool(buf, &value) || !value) - return -EINVAL; - - ret = tsl2772_prox_cal(indio_dev); - if (ret < 0) - return ret; - - ret = tsl2772_invoke_change(indio_dev); - if (ret < 0) - return ret; - - return len; -} - -static int tsl2772_read_interrupt_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - - if (chan->type == IIO_INTENSITY) - return chip->settings.als_interrupt_en; - else - return chip->settings.prox_interrupt_en; -} - -static int tsl2772_write_interrupt_config(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - int val) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - - if (chan->type == IIO_INTENSITY) - chip->settings.als_interrupt_en = val ? true : false; - else - chip->settings.prox_interrupt_en = val ? true : false; - - return tsl2772_invoke_change(indio_dev); -} - -static int tsl2772_write_event_value(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int val, int val2) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - int ret = -EINVAL, count, persistence; - u8 time; - - switch (info) { - case IIO_EV_INFO_VALUE: - if (chan->type == IIO_INTENSITY) { - switch (dir) { - case IIO_EV_DIR_RISING: - chip->settings.als_thresh_high = val; - ret = 0; - break; - case IIO_EV_DIR_FALLING: - chip->settings.als_thresh_low = val; - ret = 0; - break; - default: - break; - } - } else { - switch (dir) { - case IIO_EV_DIR_RISING: - chip->settings.prox_thres_high = val; - ret = 0; - break; - case IIO_EV_DIR_FALLING: - chip->settings.prox_thres_low = val; - ret = 0; - break; - default: - break; - } - } - break; - case IIO_EV_INFO_PERIOD: - if (chan->type == IIO_INTENSITY) - time = chip->settings.als_time; - else - time = chip->settings.prox_time; - - count = 256 - time; - persistence = ((val * 1000000) + val2) / - (count * tsl2772_int_time_avail[chip->id][3]); - - if (chan->type == IIO_INTENSITY) { - /* ALS filter values are 1, 2, 3, 5, 10, 15, ..., 60 */ - if (persistence > 3) - persistence = (persistence / 5) + 3; - - chip->settings.als_persistence = persistence; - } else { - chip->settings.prox_persistence = persistence; - } - - ret = 0; - break; - default: - break; - } - - if (ret < 0) - return ret; - - return tsl2772_invoke_change(indio_dev); -} - -static int tsl2772_read_event_value(struct iio_dev *indio_dev, - const struct iio_chan_spec *chan, - enum iio_event_type type, - enum iio_event_direction dir, - enum iio_event_info info, - int *val, int *val2) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - int filter_delay, persistence; - u8 time; - - switch (info) { - case IIO_EV_INFO_VALUE: - if (chan->type == IIO_INTENSITY) { - switch (dir) { - case IIO_EV_DIR_RISING: - *val = chip->settings.als_thresh_high; - return IIO_VAL_INT; - case IIO_EV_DIR_FALLING: - *val = chip->settings.als_thresh_low; - return IIO_VAL_INT; - default: - return -EINVAL; - } - } else { - switch (dir) { - case IIO_EV_DIR_RISING: - *val = chip->settings.prox_thres_high; - return IIO_VAL_INT; - case IIO_EV_DIR_FALLING: - *val = chip->settings.prox_thres_low; - return IIO_VAL_INT; - default: - return -EINVAL; - } - } - break; - case IIO_EV_INFO_PERIOD: - if (chan->type == IIO_INTENSITY) { - time = chip->settings.als_time; - persistence = chip->settings.als_persistence; - - /* ALS filter values are 1, 2, 3, 5, 10, 15, ..., 60 */ - if (persistence > 3) - persistence = (persistence - 3) * 5; - } else { - time = chip->settings.prox_time; - persistence = chip->settings.prox_persistence; - } - - filter_delay = persistence * (256 - time) * - tsl2772_int_time_avail[chip->id][3]; - - *val = filter_delay / 1000000; - *val2 = filter_delay % 1000000; - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } -} - -static int tsl2772_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, - int *val2, - long mask) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_PROCESSED: - switch (chan->type) { - case IIO_LIGHT: - tsl2772_get_lux(indio_dev); - *val = chip->als_cur_info.lux; - return IIO_VAL_INT; - default: - return -EINVAL; - } - case IIO_CHAN_INFO_RAW: - switch (chan->type) { - case IIO_INTENSITY: - tsl2772_get_lux(indio_dev); - if (chan->channel == 0) - *val = chip->als_cur_info.als_ch0; - else - *val = chip->als_cur_info.als_ch1; - return IIO_VAL_INT; - case IIO_PROXIMITY: - tsl2772_get_prox(indio_dev); - *val = chip->prox_data; - return IIO_VAL_INT; - default: - return -EINVAL; - } - break; - case IIO_CHAN_INFO_CALIBSCALE: - if (chan->type == IIO_LIGHT) - *val = tsl2772_als_gain[chip->settings.als_gain]; - else - *val = tsl2772_prox_gain[chip->settings.prox_gain]; - return IIO_VAL_INT; - case IIO_CHAN_INFO_CALIBBIAS: - *val = chip->settings.als_gain_trim; - return IIO_VAL_INT; - case IIO_CHAN_INFO_INT_TIME: - *val = 0; - *val2 = (256 - chip->settings.als_time) * - tsl2772_int_time_avail[chip->id][3]; - return IIO_VAL_INT_PLUS_MICRO; - default: - return -EINVAL; - } -} - -static int tsl2772_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, - int val2, - long mask) -{ - struct tsl2772_chip *chip = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_CALIBSCALE: - if (chan->type == IIO_INTENSITY) { - switch (val) { - case 1: - chip->settings.als_gain = 0; - break; - case 8: - chip->settings.als_gain = 1; - break; - case 16: - chip->settings.als_gain = 2; - break; - case 120: - chip->settings.als_gain = 3; - break; - default: - return -EINVAL; - } - } else { - switch (val) { - case 1: - chip->settings.prox_gain = 0; - break; - case 2: - chip->settings.prox_gain = 1; - break; - case 4: - chip->settings.prox_gain = 2; - break; - case 8: - chip->settings.prox_gain = 3; - break; - default: - return -EINVAL; - } - } - break; - case IIO_CHAN_INFO_CALIBBIAS: - if (val < TSL2772_ALS_GAIN_TRIM_MIN || - val > TSL2772_ALS_GAIN_TRIM_MAX) - return -EINVAL; - - chip->settings.als_gain_trim = val; - break; - case IIO_CHAN_INFO_INT_TIME: - if (val != 0 || val2 < tsl2772_int_time_avail[chip->id][1] || - val2 > tsl2772_int_time_avail[chip->id][5]) - return -EINVAL; - - chip->settings.als_time = 256 - - (val2 / tsl2772_int_time_avail[chip->id][3]); - break; - default: - return -EINVAL; - } - - return tsl2772_invoke_change(indio_dev); -} - -static DEVICE_ATTR_RW(in_illuminance0_target_input); - -static DEVICE_ATTR_WO(in_illuminance0_calibrate); - -static DEVICE_ATTR_WO(in_proximity0_calibrate); - -static DEVICE_ATTR_RW(in_illuminance0_lux_table); - -/* Use the default register values to identify the Taos device */ -static int tsl2772_device_id_verif(int id, int target) -{ - switch (target) { - case tsl2571: - case tsl2671: - case tsl2771: - return (id & 0xf0) == TRITON_ID; - case tmd2671: - case tmd2771: - return (id & 0xf0) == HALIBUT_ID; - case tsl2572: - case tsl2672: - case tmd2672: - case tsl2772: - case tmd2772: - return (id & 0xf0) == SWORDFISH_ID; - } - - return -EINVAL; -} - -static irqreturn_t tsl2772_event_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct tsl2772_chip *chip = iio_priv(indio_dev); - s64 timestamp = iio_get_time_ns(indio_dev); - int ret; - - ret = tsl2772_read_status(chip); - if (ret < 0) - return IRQ_HANDLED; - - /* What type of interrupt do we need to process */ - if (ret & TSL2772_STA_PRX_INTR) { - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, - 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_EITHER), - timestamp); - } - - if (ret & TSL2772_STA_ALS_INTR) { - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE(IIO_LIGHT, - 0, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_EITHER), - timestamp); - } - - ret = i2c_smbus_write_byte(chip->client, - TSL2772_CMD_REG | TSL2772_CMD_SPL_FN | - TSL2772_CMD_PROXALS_INT_CLR); - if (ret < 0) - dev_err(&chip->client->dev, - "%s: failed to clear interrupt status: %d\n", - __func__, ret); - - return IRQ_HANDLED; -} - -static struct attribute *tsl2772_ALS_device_attrs[] = { - &dev_attr_in_illuminance0_target_input.attr, - &dev_attr_in_illuminance0_calibrate.attr, - &dev_attr_in_illuminance0_lux_table.attr, - NULL -}; - -static struct attribute *tsl2772_PRX_device_attrs[] = { - &dev_attr_in_proximity0_calibrate.attr, - NULL -}; - -static struct attribute *tsl2772_ALSPRX_device_attrs[] = { - &dev_attr_in_illuminance0_target_input.attr, - &dev_attr_in_illuminance0_calibrate.attr, - &dev_attr_in_illuminance0_lux_table.attr, - NULL -}; - -static struct attribute *tsl2772_PRX2_device_attrs[] = { - &dev_attr_in_proximity0_calibrate.attr, - NULL -}; - -static struct attribute *tsl2772_ALSPRX2_device_attrs[] = { - &dev_attr_in_illuminance0_target_input.attr, - &dev_attr_in_illuminance0_calibrate.attr, - &dev_attr_in_illuminance0_lux_table.attr, - &dev_attr_in_proximity0_calibrate.attr, - NULL -}; - -static const struct attribute_group tsl2772_device_attr_group_tbl[] = { - [ALS] = { - .attrs = tsl2772_ALS_device_attrs, - }, - [PRX] = { - .attrs = tsl2772_PRX_device_attrs, - }, - [ALSPRX] = { - .attrs = tsl2772_ALSPRX_device_attrs, - }, - [PRX2] = { - .attrs = tsl2772_PRX2_device_attrs, - }, - [ALSPRX2] = { - .attrs = tsl2772_ALSPRX2_device_attrs, - }, -}; - -#define TSL2772_DEVICE_INFO(type)[type] = \ - { \ - .attrs = &tsl2772_device_attr_group_tbl[type], \ - .read_raw = &tsl2772_read_raw, \ - .read_avail = &tsl2772_read_avail, \ - .write_raw = &tsl2772_write_raw, \ - .read_event_value = &tsl2772_read_event_value, \ - .write_event_value = &tsl2772_write_event_value, \ - .read_event_config = &tsl2772_read_interrupt_config, \ - .write_event_config = &tsl2772_write_interrupt_config, \ - } - -static const struct iio_info tsl2772_device_info[] = { - TSL2772_DEVICE_INFO(ALS), - TSL2772_DEVICE_INFO(PRX), - TSL2772_DEVICE_INFO(ALSPRX), - TSL2772_DEVICE_INFO(PRX2), - TSL2772_DEVICE_INFO(ALSPRX2), -}; - -static const struct iio_event_spec tsl2772_events[] = { - { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_RISING, - .mask_separate = BIT(IIO_EV_INFO_VALUE), - }, { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_VALUE), - }, { - .type = IIO_EV_TYPE_THRESH, - .dir = IIO_EV_DIR_EITHER, - .mask_separate = BIT(IIO_EV_INFO_PERIOD) | - BIT(IIO_EV_INFO_ENABLE), - }, -}; - -static const struct tsl2772_chip_info tsl2772_chip_info_tbl[] = { - [ALS] = { - .channel_with_events = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE) | - BIT(IIO_CHAN_INFO_CALIBBIAS), - .info_mask_separate_available = - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - .event_spec = tsl2772_events, - .num_event_specs = ARRAY_SIZE(tsl2772_events), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 1, - }, - }, - .channel_without_events = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE) | - BIT(IIO_CHAN_INFO_CALIBBIAS), - .info_mask_separate_available = - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 1, - }, - }, - .chan_table_elements = 3, - .info = &tsl2772_device_info[ALS], - }, - [PRX] = { - .channel_with_events = { - { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .event_spec = tsl2772_events, - .num_event_specs = ARRAY_SIZE(tsl2772_events), - }, - }, - .channel_without_events = { - { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - }, - }, - .chan_table_elements = 1, - .info = &tsl2772_device_info[PRX], - }, - [ALSPRX] = { - .channel_with_events = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE) | - BIT(IIO_CHAN_INFO_CALIBBIAS), - .info_mask_separate_available = - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - .event_spec = tsl2772_events, - .num_event_specs = ARRAY_SIZE(tsl2772_events), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 1, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - }, { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - .event_spec = tsl2772_events, - .num_event_specs = ARRAY_SIZE(tsl2772_events), - }, - }, - .channel_without_events = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE) | - BIT(IIO_CHAN_INFO_CALIBBIAS), - .info_mask_separate_available = - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 1, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - }, { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - }, - }, - .chan_table_elements = 4, - .info = &tsl2772_device_info[ALSPRX], - }, - [PRX2] = { - .channel_with_events = { - { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - .info_mask_separate_available = - BIT(IIO_CHAN_INFO_CALIBSCALE), - .event_spec = tsl2772_events, - .num_event_specs = ARRAY_SIZE(tsl2772_events), - }, - }, - .channel_without_events = { - { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - .info_mask_separate_available = - BIT(IIO_CHAN_INFO_CALIBSCALE), - }, - }, - .chan_table_elements = 1, - .info = &tsl2772_device_info[PRX2], - }, - [ALSPRX2] = { - .channel_with_events = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE) | - BIT(IIO_CHAN_INFO_CALIBBIAS), - .info_mask_separate_available = - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - .event_spec = tsl2772_events, - .num_event_specs = ARRAY_SIZE(tsl2772_events), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 1, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - }, { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - .info_mask_separate_available = - BIT(IIO_CHAN_INFO_CALIBSCALE), - .event_spec = tsl2772_events, - .num_event_specs = ARRAY_SIZE(tsl2772_events), - }, - }, - .channel_without_events = { - { - .type = IIO_LIGHT, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE) | - BIT(IIO_CHAN_INFO_CALIBBIAS), - .info_mask_separate_available = - BIT(IIO_CHAN_INFO_INT_TIME) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - }, { - .type = IIO_INTENSITY, - .indexed = 1, - .channel = 1, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), - }, { - .type = IIO_PROXIMITY, - .indexed = 1, - .channel = 0, - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | - BIT(IIO_CHAN_INFO_CALIBSCALE), - .info_mask_separate_available = - BIT(IIO_CHAN_INFO_CALIBSCALE), - }, - }, - .chan_table_elements = 4, - .info = &tsl2772_device_info[ALSPRX2], - }, -}; - -static int tsl2772_probe(struct i2c_client *clientp, - const struct i2c_device_id *id) -{ - struct iio_dev *indio_dev; - struct tsl2772_chip *chip; - int ret; - - indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip)); - if (!indio_dev) - return -ENOMEM; - - chip = iio_priv(indio_dev); - chip->client = clientp; - i2c_set_clientdata(clientp, indio_dev); - - ret = i2c_smbus_read_byte_data(chip->client, - TSL2772_CMD_REG | TSL2772_CHIPID); - if (ret < 0) - return ret; - - if (tsl2772_device_id_verif(ret, id->driver_data) <= 0) { - dev_info(&chip->client->dev, - "%s: i2c device found does not match expected id\n", - __func__); - return -EINVAL; - } - - ret = i2c_smbus_write_byte(clientp, TSL2772_CMD_REG | TSL2772_CNTRL); - if (ret < 0) { - dev_err(&clientp->dev, - "%s: Failed to write to CMD register: %d\n", - __func__, ret); - return ret; - } - - mutex_init(&chip->als_mutex); - mutex_init(&chip->prox_mutex); - - chip->tsl2772_chip_status = TSL2772_CHIP_UNKNOWN; - chip->pdata = dev_get_platdata(&clientp->dev); - chip->id = id->driver_data; - chip->chip_info = - &tsl2772_chip_info_tbl[device_channel_config[id->driver_data]]; - - indio_dev->info = chip->chip_info->info; - indio_dev->dev.parent = &clientp->dev; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->name = chip->client->name; - indio_dev->num_channels = chip->chip_info->chan_table_elements; - - if (clientp->irq) { - indio_dev->channels = chip->chip_info->channel_with_events; - - ret = devm_request_threaded_irq(&clientp->dev, clientp->irq, - NULL, - &tsl2772_event_handler, - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, - "TSL2772_event", - indio_dev); - if (ret) { - dev_err(&clientp->dev, - "%s: irq request failed\n", __func__); - return ret; - } - } else { - indio_dev->channels = chip->chip_info->channel_without_events; - } - - tsl2772_defaults(chip); - ret = tsl2772_chip_on(indio_dev); - if (ret < 0) - return ret; - - ret = iio_device_register(indio_dev); - if (ret) { - tsl2772_chip_off(indio_dev); - dev_err(&clientp->dev, - "%s: iio registration failed\n", __func__); - return ret; - } - - return 0; -} - -static int tsl2772_suspend(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - - return tsl2772_chip_off(indio_dev); -} - -static int tsl2772_resume(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - - return tsl2772_chip_on(indio_dev); -} - -static int tsl2772_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - - tsl2772_chip_off(indio_dev); - - iio_device_unregister(indio_dev); - - return 0; -} - -static const struct i2c_device_id tsl2772_idtable[] = { - { "tsl2571", tsl2571 }, - { "tsl2671", tsl2671 }, - { "tmd2671", tmd2671 }, - { "tsl2771", tsl2771 }, - { "tmd2771", tmd2771 }, - { "tsl2572", tsl2572 }, - { "tsl2672", tsl2672 }, - { "tmd2672", tmd2672 }, - { "tsl2772", tsl2772 }, - { "tmd2772", tmd2772 }, - {} -}; - -MODULE_DEVICE_TABLE(i2c, tsl2772_idtable); - -static const struct of_device_id tsl2772_of_match[] = { - { .compatible = "amstaos,tsl2571" }, - { .compatible = "amstaos,tsl2671" }, - { .compatible = "amstaos,tmd2671" }, - { .compatible = "amstaos,tsl2771" }, - { .compatible = "amstaos,tmd2771" }, - { .compatible = "amstaos,tsl2572" }, - { .compatible = "amstaos,tsl2672" }, - { .compatible = "amstaos,tmd2672" }, - { .compatible = "amstaos,tsl2772" }, - { .compatible = "amstaos,tmd2772" }, - {} -}; -MODULE_DEVICE_TABLE(of, tsl2772_of_match); - -static const struct dev_pm_ops tsl2772_pm_ops = { - .suspend = tsl2772_suspend, - .resume = tsl2772_resume, -}; - -static struct i2c_driver tsl2772_driver = { - .driver = { - .name = "tsl2772", - .of_match_table = tsl2772_of_match, - .pm = &tsl2772_pm_ops, - }, - .id_table = tsl2772_idtable, - .probe = tsl2772_probe, - .remove = tsl2772_remove, -}; - -module_i2c_driver(tsl2772_driver); - -MODULE_AUTHOR("J. August Brenner "); -MODULE_AUTHOR("Brian Masney "); -MODULE_DESCRIPTION("TAOS tsl2772 ambient and proximity light sensor driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/iio/light/tsl2772.h b/drivers/staging/iio/light/tsl2772.h deleted file mode 100644 index f8ade15a35e2..000000000000 --- a/drivers/staging/iio/light/tsl2772.h +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Device driver for monitoring ambient light intensity (lux) - * and proximity (prox) within the TAOS TSL2772 family of devices. - * - * Copyright (c) 2012, TAOS Corporation. - * Copyright (c) 2017-2018 Brian Masney - */ - -#ifndef __TSL2772_H -#define __TSL2772_H - -struct tsl2772_lux { - unsigned int ch0; - unsigned int ch1; -}; - -/* Max number of segments allowable in LUX table */ -#define TSL2772_MAX_LUX_TABLE_SIZE 6 -/* The default LUX tables all have 3 elements. */ -#define TSL2772_DEF_LUX_TABLE_SZ 3 -#define TSL2772_DEFAULT_TABLE_BYTES (sizeof(struct tsl2772_lux) * \ - TSL2772_DEF_LUX_TABLE_SZ) - -/* Proximity diode to use */ -#define TSL2772_DIODE0 0x01 -#define TSL2772_DIODE1 0x02 -#define TSL2772_DIODE_BOTH 0x03 - -/* LED Power */ -#define TSL2772_100_mA 0x00 -#define TSL2772_50_mA 0x01 -#define TSL2772_25_mA 0x02 -#define TSL2772_13_mA 0x03 - -/** - * struct tsl2772_settings - Settings for the tsl2772 driver - * @als_time: Integration time of the ALS channel ADCs in 2.73 ms - * increments. Total integration time is - * (256 - als_time) * 2.73. - * @als_gain: Index into the tsl2772_als_gain array. - * @als_gain_trim: Default gain trim to account for aperture effects. - * @wait_time: Time between proximity and ALS cycles in 2.73 - * periods. - * @prox_time: Integration time of the proximity ADC in 2.73 ms - * increments. Total integration time is - * (256 - prx_time) * 2.73. - * @prox_gain: Index into the tsl2772_prx_gain array. - * @als_prox_config: The value of the ALS / Proximity configuration - * register. - * @als_cal_target: Known external ALS reading for calibration. - * @als_persistence: H/W Filters, Number of 'out of limits' ALS readings. - * @als_interrupt_en: Enable/Disable ALS interrupts - * @als_thresh_low: CH0 'low' count to trigger interrupt. - * @als_thresh_high: CH0 'high' count to trigger interrupt. - * @prox_persistence: H/W Filters, Number of 'out of limits' proximity - * readings. - * @prox_interrupt_en: Enable/Disable proximity interrupts. - * @prox_thres_low: Low threshold proximity detection. - * @prox_thres_high: High threshold proximity detection. - * @prox_pulse_count: Number if proximity emitter pulses. - * @prox_max_samples_cal: The number of samples that are taken when performing - * a proximity calibration. - * @prox_diode Which diode(s) to use for driving the external - * LED(s) for proximity sensing. - * @prox_power The amount of power to use for the external LED(s). - */ -struct tsl2772_settings { - int als_time; - int als_gain; - int als_gain_trim; - int wait_time; - int prox_time; - int prox_gain; - int als_prox_config; - int als_cal_target; - u8 als_persistence; - bool als_interrupt_en; - int als_thresh_low; - int als_thresh_high; - u8 prox_persistence; - bool prox_interrupt_en; - int prox_thres_low; - int prox_thres_high; - int prox_pulse_count; - int prox_max_samples_cal; - int prox_diode; - int prox_power; -}; - -/** - * struct tsl2772_platform_data - Platform callback, glass and defaults - * @platform_lux_table: Device specific glass coefficents - * @platform_default_settings: Device specific power on defaults - */ -struct tsl2772_platform_data { - struct tsl2772_lux platform_lux_table[TSL2772_MAX_LUX_TABLE_SIZE]; - struct tsl2772_settings *platform_default_settings; -}; - -#endif /* __TSL2772_H */ diff --git a/include/linux/platform_data/tsl2772.h b/include/linux/platform_data/tsl2772.h new file mode 100644 index 000000000000..f8ade15a35e2 --- /dev/null +++ b/include/linux/platform_data/tsl2772.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Device driver for monitoring ambient light intensity (lux) + * and proximity (prox) within the TAOS TSL2772 family of devices. + * + * Copyright (c) 2012, TAOS Corporation. + * Copyright (c) 2017-2018 Brian Masney + */ + +#ifndef __TSL2772_H +#define __TSL2772_H + +struct tsl2772_lux { + unsigned int ch0; + unsigned int ch1; +}; + +/* Max number of segments allowable in LUX table */ +#define TSL2772_MAX_LUX_TABLE_SIZE 6 +/* The default LUX tables all have 3 elements. */ +#define TSL2772_DEF_LUX_TABLE_SZ 3 +#define TSL2772_DEFAULT_TABLE_BYTES (sizeof(struct tsl2772_lux) * \ + TSL2772_DEF_LUX_TABLE_SZ) + +/* Proximity diode to use */ +#define TSL2772_DIODE0 0x01 +#define TSL2772_DIODE1 0x02 +#define TSL2772_DIODE_BOTH 0x03 + +/* LED Power */ +#define TSL2772_100_mA 0x00 +#define TSL2772_50_mA 0x01 +#define TSL2772_25_mA 0x02 +#define TSL2772_13_mA 0x03 + +/** + * struct tsl2772_settings - Settings for the tsl2772 driver + * @als_time: Integration time of the ALS channel ADCs in 2.73 ms + * increments. Total integration time is + * (256 - als_time) * 2.73. + * @als_gain: Index into the tsl2772_als_gain array. + * @als_gain_trim: Default gain trim to account for aperture effects. + * @wait_time: Time between proximity and ALS cycles in 2.73 + * periods. + * @prox_time: Integration time of the proximity ADC in 2.73 ms + * increments. Total integration time is + * (256 - prx_time) * 2.73. + * @prox_gain: Index into the tsl2772_prx_gain array. + * @als_prox_config: The value of the ALS / Proximity configuration + * register. + * @als_cal_target: Known external ALS reading for calibration. + * @als_persistence: H/W Filters, Number of 'out of limits' ALS readings. + * @als_interrupt_en: Enable/Disable ALS interrupts + * @als_thresh_low: CH0 'low' count to trigger interrupt. + * @als_thresh_high: CH0 'high' count to trigger interrupt. + * @prox_persistence: H/W Filters, Number of 'out of limits' proximity + * readings. + * @prox_interrupt_en: Enable/Disable proximity interrupts. + * @prox_thres_low: Low threshold proximity detection. + * @prox_thres_high: High threshold proximity detection. + * @prox_pulse_count: Number if proximity emitter pulses. + * @prox_max_samples_cal: The number of samples that are taken when performing + * a proximity calibration. + * @prox_diode Which diode(s) to use for driving the external + * LED(s) for proximity sensing. + * @prox_power The amount of power to use for the external LED(s). + */ +struct tsl2772_settings { + int als_time; + int als_gain; + int als_gain_trim; + int wait_time; + int prox_time; + int prox_gain; + int als_prox_config; + int als_cal_target; + u8 als_persistence; + bool als_interrupt_en; + int als_thresh_low; + int als_thresh_high; + u8 prox_persistence; + bool prox_interrupt_en; + int prox_thres_low; + int prox_thres_high; + int prox_pulse_count; + int prox_max_samples_cal; + int prox_diode; + int prox_power; +}; + +/** + * struct tsl2772_platform_data - Platform callback, glass and defaults + * @platform_lux_table: Device specific glass coefficents + * @platform_default_settings: Device specific power on defaults + */ +struct tsl2772_platform_data { + struct tsl2772_lux platform_lux_table[TSL2772_MAX_LUX_TABLE_SIZE]; + struct tsl2772_settings *platform_default_settings; +}; + +#endif /* __TSL2772_H */ -- cgit v1.2.3-71-gd317 From ed582db639cfe65e2d901fca1be8fd813a18fec4 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 15 May 2018 17:19:17 +0200 Subject: iio: adc: stm32-dfsdm: include stm32-dfsdm-adc.h Fix the following sparse warnings: CHECK drivers/iio/adc/stm32-dfsdm-adc.c symbol 'stm32_dfsdm_get_buff_cb' was not declared. Should it be static? symbol 'stm32_dfsdm_release_buff_cb' was not declared. Should it be static? BTW, move interrupt.h to sort headers alphabetically. Signed-off-by: Fabrice Gasnier Signed-off-by: Jonathan Cameron --- drivers/iio/adc/stm32-dfsdm-adc.c | 4 ++-- include/linux/iio/adc/stm32-dfsdm-adc.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c index 1b78becaba5d..31462aef7238 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -8,11 +8,11 @@ #include #include -#include +#include #include #include -#include #include +#include #include #include #include diff --git a/include/linux/iio/adc/stm32-dfsdm-adc.h b/include/linux/iio/adc/stm32-dfsdm-adc.h index e7dc7a542a4e..0da298b41737 100644 --- a/include/linux/iio/adc/stm32-dfsdm-adc.h +++ b/include/linux/iio/adc/stm32-dfsdm-adc.h @@ -9,6 +9,8 @@ #ifndef STM32_DFSDM_ADC_H #define STM32_DFSDM_ADC_H +#include + int stm32_dfsdm_get_buff_cb(struct iio_dev *iio_dev, int (*cb)(const void *data, size_t size, void *private), -- cgit v1.2.3-71-gd317 From 05e98465e08a58d7f8f577281f0c98c71c624c4b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 1 Jun 2018 20:36:30 +0200 Subject: ncpfs: remove uapi .h files Now that ncpfs is removed from the tree, there is no need to keep the uapi header files around as no one uses them, and it is not a feature that the kernel supports anymore. Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/ncp.h | 202 ----------------------------------------- include/uapi/linux/ncp_fs.h | 147 ------------------------------ include/uapi/linux/ncp_mount.h | 72 --------------- include/uapi/linux/ncp_no.h | 20 ---- 4 files changed, 441 deletions(-) delete mode 100644 include/uapi/linux/ncp.h delete mode 100644 include/uapi/linux/ncp_fs.h delete mode 100644 include/uapi/linux/ncp_mount.h delete mode 100644 include/uapi/linux/ncp_no.h (limited to 'include') diff --git a/include/uapi/linux/ncp.h b/include/uapi/linux/ncp.h deleted file mode 100644 index ca6f3d42c88f..000000000000 --- a/include/uapi/linux/ncp.h +++ /dev/null @@ -1,202 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * ncp.h - * - * Copyright (C) 1995 by Volker Lendecke - * Modified for sparc by J.F. Chadima - * Modified for __constant_ntoh by Frank A. Vorstenbosch - * - */ - -#ifndef _LINUX_NCP_H -#define _LINUX_NCP_H - -#include - -#define NCP_PTYPE (0x11) -#define NCP_PORT (0x0451) - -#define NCP_ALLOC_SLOT_REQUEST (0x1111) -#define NCP_REQUEST (0x2222) -#define NCP_DEALLOC_SLOT_REQUEST (0x5555) - -struct ncp_request_header { - __u16 type; - __u8 sequence; - __u8 conn_low; - __u8 task; - __u8 conn_high; - __u8 function; - __u8 data[0]; -} __attribute__((packed)); - -#define NCP_REPLY (0x3333) -#define NCP_WATCHDOG (0x3E3E) -#define NCP_POSITIVE_ACK (0x9999) - -struct ncp_reply_header { - __u16 type; - __u8 sequence; - __u8 conn_low; - __u8 task; - __u8 conn_high; - __u8 completion_code; - __u8 connection_state; - __u8 data[0]; -} __attribute__((packed)); - -#define NCP_VOLNAME_LEN (16) -#define NCP_NUMBER_OF_VOLUMES (256) -struct ncp_volume_info { - __u32 total_blocks; - __u32 free_blocks; - __u32 purgeable_blocks; - __u32 not_yet_purgeable_blocks; - __u32 total_dir_entries; - __u32 available_dir_entries; - __u8 sectors_per_block; - char volume_name[NCP_VOLNAME_LEN + 1]; -}; - -#define AR_READ (cpu_to_le16(1)) -#define AR_WRITE (cpu_to_le16(2)) -#define AR_EXCLUSIVE (cpu_to_le16(0x20)) - -#define NCP_FILE_ID_LEN 6 - -/* Defines for Name Spaces */ -#define NW_NS_DOS 0 -#define NW_NS_MAC 1 -#define NW_NS_NFS 2 -#define NW_NS_FTAM 3 -#define NW_NS_OS2 4 - -/* Defines for ReturnInformationMask */ -#define RIM_NAME (cpu_to_le32(1)) -#define RIM_SPACE_ALLOCATED (cpu_to_le32(2)) -#define RIM_ATTRIBUTES (cpu_to_le32(4)) -#define RIM_DATA_SIZE (cpu_to_le32(8)) -#define RIM_TOTAL_SIZE (cpu_to_le32(0x10)) -#define RIM_EXT_ATTR_INFO (cpu_to_le32(0x20)) -#define RIM_ARCHIVE (cpu_to_le32(0x40)) -#define RIM_MODIFY (cpu_to_le32(0x80)) -#define RIM_CREATION (cpu_to_le32(0x100)) -#define RIM_OWNING_NAMESPACE (cpu_to_le32(0x200)) -#define RIM_DIRECTORY (cpu_to_le32(0x400)) -#define RIM_RIGHTS (cpu_to_le32(0x800)) -#define RIM_ALL (cpu_to_le32(0xFFF)) -#define RIM_COMPRESSED_INFO (cpu_to_le32(0x80000000)) - -/* Defines for NSInfoBitMask */ -#define NSIBM_NFS_NAME 0x0001 -#define NSIBM_NFS_MODE 0x0002 -#define NSIBM_NFS_GID 0x0004 -#define NSIBM_NFS_NLINKS 0x0008 -#define NSIBM_NFS_RDEV 0x0010 -#define NSIBM_NFS_LINK 0x0020 -#define NSIBM_NFS_CREATED 0x0040 -#define NSIBM_NFS_UID 0x0080 -#define NSIBM_NFS_ACSFLAG 0x0100 -#define NSIBM_NFS_MYFLAG 0x0200 - -/* open/create modes */ -#define OC_MODE_OPEN 0x01 -#define OC_MODE_TRUNCATE 0x02 -#define OC_MODE_REPLACE 0x02 -#define OC_MODE_CREATE 0x08 - -/* open/create results */ -#define OC_ACTION_NONE 0x00 -#define OC_ACTION_OPEN 0x01 -#define OC_ACTION_CREATE 0x02 -#define OC_ACTION_TRUNCATE 0x04 -#define OC_ACTION_REPLACE 0x04 - -/* access rights attributes */ -#ifndef AR_READ_ONLY -#define AR_READ_ONLY 0x0001 -#define AR_WRITE_ONLY 0x0002 -#define AR_DENY_READ 0x0004 -#define AR_DENY_WRITE 0x0008 -#define AR_COMPATIBILITY 0x0010 -#define AR_WRITE_THROUGH 0x0040 -#define AR_OPEN_COMPRESSED 0x0100 -#endif - -struct nw_nfs_info { - __u32 mode; - __u32 rdev; -}; - -struct nw_info_struct { - __u32 spaceAlloc; - __le32 attributes; - __u16 flags; - __le32 dataStreamSize; - __le32 totalStreamSize; - __u16 numberOfStreams; - __le16 creationTime; - __le16 creationDate; - __u32 creatorID; - __le16 modifyTime; - __le16 modifyDate; - __u32 modifierID; - __le16 lastAccessDate; - __u16 archiveTime; - __u16 archiveDate; - __u32 archiverID; - __u16 inheritedRightsMask; - __le32 dirEntNum; - __le32 DosDirNum; - __u32 volNumber; - __u32 EADataSize; - __u32 EAKeyCount; - __u32 EAKeySize; - __u32 NSCreator; - __u8 nameLen; - __u8 entryName[256]; - /* libncp may depend on there being nothing after entryName */ -#ifdef __KERNEL__ - struct nw_nfs_info nfs; -#endif -} __attribute__((packed)); - -/* modify mask - use with MODIFY_DOS_INFO structure */ -#define DM_ATTRIBUTES (cpu_to_le32(0x02)) -#define DM_CREATE_DATE (cpu_to_le32(0x04)) -#define DM_CREATE_TIME (cpu_to_le32(0x08)) -#define DM_CREATOR_ID (cpu_to_le32(0x10)) -#define DM_ARCHIVE_DATE (cpu_to_le32(0x20)) -#define DM_ARCHIVE_TIME (cpu_to_le32(0x40)) -#define DM_ARCHIVER_ID (cpu_to_le32(0x80)) -#define DM_MODIFY_DATE (cpu_to_le32(0x0100)) -#define DM_MODIFY_TIME (cpu_to_le32(0x0200)) -#define DM_MODIFIER_ID (cpu_to_le32(0x0400)) -#define DM_LAST_ACCESS_DATE (cpu_to_le32(0x0800)) -#define DM_INHERITED_RIGHTS_MASK (cpu_to_le32(0x1000)) -#define DM_MAXIMUM_SPACE (cpu_to_le32(0x2000)) - -struct nw_modify_dos_info { - __le32 attributes; - __le16 creationDate; - __le16 creationTime; - __u32 creatorID; - __le16 modifyDate; - __le16 modifyTime; - __u32 modifierID; - __u16 archiveDate; - __u16 archiveTime; - __u32 archiverID; - __le16 lastAccessDate; - __u16 inheritanceGrantMask; - __u16 inheritanceRevokeMask; - __u32 maximumSpace; -} __attribute__((packed)); - -struct nw_search_sequence { - __u8 volNumber; - __u32 dirBase; - __u32 sequence; -} __attribute__((packed)); - -#endif /* _LINUX_NCP_H */ diff --git a/include/uapi/linux/ncp_fs.h b/include/uapi/linux/ncp_fs.h deleted file mode 100644 index e76a44229d2f..000000000000 --- a/include/uapi/linux/ncp_fs.h +++ /dev/null @@ -1,147 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * ncp_fs.h - * - * Copyright (C) 1995, 1996 by Volker Lendecke - * - */ - -#ifndef _LINUX_NCP_FS_H -#define _LINUX_NCP_FS_H - -#include -#include -#include -#include - -#include -#include - -/* - * ioctl commands - */ - -struct ncp_ioctl_request { - unsigned int function; - unsigned int size; - char __user *data; -}; - -struct ncp_fs_info { - int version; - struct sockaddr_ipx addr; - __kernel_uid_t mounted_uid; - int connection; /* Connection number the server assigned us */ - int buffer_size; /* The negotiated buffer size, to be - used for read/write requests! */ - - int volume_number; - __le32 directory_id; -}; - -struct ncp_fs_info_v2 { - int version; - unsigned long mounted_uid; - unsigned int connection; - unsigned int buffer_size; - - unsigned int volume_number; - __le32 directory_id; - - __u32 dummy1; - __u32 dummy2; - __u32 dummy3; -}; - -struct ncp_sign_init -{ - char sign_root[8]; - char sign_last[16]; -}; - -struct ncp_lock_ioctl -{ -#define NCP_LOCK_LOG 0 -#define NCP_LOCK_SH 1 -#define NCP_LOCK_EX 2 -#define NCP_LOCK_CLEAR 256 - int cmd; - int origin; - unsigned int offset; - unsigned int length; -#define NCP_LOCK_DEFAULT_TIMEOUT 18 -#define NCP_LOCK_MAX_TIMEOUT 180 - int timeout; -}; - -struct ncp_setroot_ioctl -{ - int volNumber; - int namespace; - __le32 dirEntNum; -}; - -struct ncp_objectname_ioctl -{ -#define NCP_AUTH_NONE 0x00 -#define NCP_AUTH_BIND 0x31 -#define NCP_AUTH_NDS 0x32 - int auth_type; - size_t object_name_len; - void __user * object_name; /* a userspace data, in most cases user name */ -}; - -struct ncp_privatedata_ioctl -{ - size_t len; - void __user * data; /* ~1000 for NDS */ -}; - -/* NLS charsets by ioctl */ -#define NCP_IOCSNAME_LEN 20 -struct ncp_nls_ioctl -{ - unsigned char codepage[NCP_IOCSNAME_LEN+1]; - unsigned char iocharset[NCP_IOCSNAME_LEN+1]; -}; - -#define NCP_IOC_NCPREQUEST _IOR('n', 1, struct ncp_ioctl_request) -#define NCP_IOC_GETMOUNTUID _IOW('n', 2, __kernel_old_uid_t) -#define NCP_IOC_GETMOUNTUID2 _IOW('n', 2, unsigned long) - -#define NCP_IOC_CONN_LOGGED_IN _IO('n', 3) - -#define NCP_GET_FS_INFO_VERSION (1) -#define NCP_IOC_GET_FS_INFO _IOWR('n', 4, struct ncp_fs_info) -#define NCP_GET_FS_INFO_VERSION_V2 (2) -#define NCP_IOC_GET_FS_INFO_V2 _IOWR('n', 4, struct ncp_fs_info_v2) - -#define NCP_IOC_SIGN_INIT _IOR('n', 5, struct ncp_sign_init) -#define NCP_IOC_SIGN_WANTED _IOR('n', 6, int) -#define NCP_IOC_SET_SIGN_WANTED _IOW('n', 6, int) - -#define NCP_IOC_LOCKUNLOCK _IOR('n', 7, struct ncp_lock_ioctl) - -#define NCP_IOC_GETROOT _IOW('n', 8, struct ncp_setroot_ioctl) -#define NCP_IOC_SETROOT _IOR('n', 8, struct ncp_setroot_ioctl) - -#define NCP_IOC_GETOBJECTNAME _IOWR('n', 9, struct ncp_objectname_ioctl) -#define NCP_IOC_SETOBJECTNAME _IOR('n', 9, struct ncp_objectname_ioctl) -#define NCP_IOC_GETPRIVATEDATA _IOWR('n', 10, struct ncp_privatedata_ioctl) -#define NCP_IOC_SETPRIVATEDATA _IOR('n', 10, struct ncp_privatedata_ioctl) - -#define NCP_IOC_GETCHARSETS _IOWR('n', 11, struct ncp_nls_ioctl) -#define NCP_IOC_SETCHARSETS _IOR('n', 11, struct ncp_nls_ioctl) - -#define NCP_IOC_GETDENTRYTTL _IOW('n', 12, __u32) -#define NCP_IOC_SETDENTRYTTL _IOR('n', 12, __u32) - -/* - * The packet size to allocate. One page should be enough. - */ -#define NCP_PACKET_SIZE 4070 - -#define NCP_MAXPATHLEN 255 -#define NCP_MAXNAMELEN 14 - -#endif /* _LINUX_NCP_FS_H */ diff --git a/include/uapi/linux/ncp_mount.h b/include/uapi/linux/ncp_mount.h deleted file mode 100644 index 9bdbcd68c329..000000000000 --- a/include/uapi/linux/ncp_mount.h +++ /dev/null @@ -1,72 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * ncp_mount.h - * - * Copyright (C) 1995, 1996 by Volker Lendecke - * - */ - -#ifndef _LINUX_NCP_MOUNT_H -#define _LINUX_NCP_MOUNT_H - -#include -#include - -#define NCP_MOUNT_VERSION 3 /* Binary */ - -/* Values for flags */ -#define NCP_MOUNT_SOFT 0x0001 -#define NCP_MOUNT_INTR 0x0002 -#define NCP_MOUNT_STRONG 0x0004 /* enable delete/rename of r/o files */ -#define NCP_MOUNT_NO_OS2 0x0008 /* do not use OS/2 (LONG) namespace */ -#define NCP_MOUNT_NO_NFS 0x0010 /* do not use NFS namespace */ -#define NCP_MOUNT_EXTRAS 0x0020 -#define NCP_MOUNT_SYMLINKS 0x0040 /* enable symlinks */ -#define NCP_MOUNT_NFS_EXTRAS 0x0080 /* Enable use of NFS NS meta-info */ - -struct ncp_mount_data { - int version; - unsigned int ncp_fd; /* The socket to the ncp port */ - __kernel_uid_t mounted_uid; /* Who may umount() this filesystem? */ - __kernel_pid_t wdog_pid; /* Who cares for our watchdog packets? */ - - unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; - unsigned int time_out; /* How long should I wait after - sending a NCP request? */ - unsigned int retry_count; /* And how often should I retry? */ - unsigned int flags; - - __kernel_uid_t uid; - __kernel_gid_t gid; - __kernel_mode_t file_mode; - __kernel_mode_t dir_mode; -}; - -#define NCP_MOUNT_VERSION_V4 (4) /* Binary or text */ - -struct ncp_mount_data_v4 { - int version; - unsigned long flags; /* NCP_MOUNT_* flags */ - /* MIPS uses long __kernel_uid_t, but... */ - /* we neever pass -1, so it is safe */ - unsigned long mounted_uid; /* Who may umount() this filesystem? */ - /* MIPS uses long __kernel_pid_t */ - long wdog_pid; /* Who cares for our watchdog packets? */ - - unsigned int ncp_fd; /* The socket to the ncp port */ - unsigned int time_out; /* How long should I wait after - sending a NCP request? */ - unsigned int retry_count; /* And how often should I retry? */ - - /* MIPS uses long __kernel_uid_t... */ - /* we never pass -1, so it is safe */ - unsigned long uid; - unsigned long gid; - /* MIPS uses unsigned long __kernel_mode_t */ - unsigned long file_mode; - unsigned long dir_mode; -}; - -#define NCP_MOUNT_VERSION_V5 (5) /* Text only */ - -#endif diff --git a/include/uapi/linux/ncp_no.h b/include/uapi/linux/ncp_no.h deleted file mode 100644 index 654d7c7f5d92..000000000000 --- a/include/uapi/linux/ncp_no.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _NCP_NO -#define _NCP_NO - -/* these define the attribute byte as seen by NCP */ -#define aRONLY (__cpu_to_le32(1)) -#define aHIDDEN (__cpu_to_le32(2)) -#define aSYSTEM (__cpu_to_le32(4)) -#define aEXECUTE (__cpu_to_le32(8)) -#define aDIR (__cpu_to_le32(0x10)) -#define aARCH (__cpu_to_le32(0x20)) -#define aSHARED (__cpu_to_le32(0x80)) -#define aDONTSUBALLOCATE (__cpu_to_le32(1L<<11)) -#define aTRANSACTIONAL (__cpu_to_le32(1L<<12)) -#define aPURGE (__cpu_to_le32(1L<<16)) -#define aRENAMEINHIBIT (__cpu_to_le32(1L<<17)) -#define aDELETEINHIBIT (__cpu_to_le32(1L<<18)) -#define aDONTCOMPRESS (__cpu_to_le32(1L<<27)) - -#endif /* _NCP_NO */ -- cgit v1.2.3-71-gd317