Fourth round of IIO new drivers, functionality and cleanups for the 3.13 cycle.
New Drivers * cm36651 combined RGB light and proximity sensor. Core improvements * Some more fixes and cleanups related to buffers. These include the second half of a series which went is as fixes. The basis for delaying until the next merge window is that some are too invasive for this late in a cycle and others only effect code paths current unused in the mainline tree. In this case we have: * protecting against concurrent userspace access * fixing a memory leak if a device goes away * avoiding always reallocating the buffer whether or not it has changed (a bug fix, but one with no functional changes other than a small speed improvement.) * Add reference counting for buffers to ensure they hang around if open from userspace or in kernel when the device is forcefully removed. * Return -ENODEV for buffer access operations when the device has gone away. * Add proper locking for iio_update_buffers (currently we only have one buffer per device in mainline, but an input bridge driver is under development which would make this bug 'real'.) * Wake up anyone waiting on a buffer if the device is unregistered. A subsequent read will fail, notifying userspace that the device is no longer there rather than having it wait possibly for ever. * Move the iio_sw_preenable functionality into the core. This avoids drivers having to 'know' about how the buffers are implemented and is called by almost all drivers anyway. Those that don't call it are not harmed by it being called. * New registration approach for information (i.e. sysfs attributes) about events. Much more generic and now similar to how the equivalent is handled for channel information. The events infrastructure had been left behind by other changes so this brings it back in line. * Using the new events registration approach, add a hysterisis event_info element and apply this to those drivers with this property. * A little unitialized variable bug in the generic_buffer.c example. * Factor out the code for freeing lists of IIO Device attributes to avoid some repitition. Driver cleanups * At91 driver gains touch screen support and some related fixes. * Follow up series of patches removing the now redundant iio_sw_buffer_preenable calls. * Lots of conversions to the new event registration methods. * Another round of hmc5843 cleanups as that driver moves towards graduating from staging. * Make some SoC drivers buildable if COMPILE_TEST is used. Follow up fixes for a few bits and bobs that revealed. * Add explicit includes of linux/of.h to those drivers making us of linux/of.h -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJSYmsbAAoJEFSFNJnE9BaIuvsQAIxknxxAVBl8Jj8sqFJM/TJh /iBP4c7HPsiZUFAyt59PONvwaY2iacTjWYx55mPsHpLXtVG4nsTj/E21lSPsp90D YuXLmT8vU4kN3X1wJkiUmBYzO6mqHlBw8Z+dcLB4N4xOpHgvFTSuc12Gdmilbna2 APjAm513G6MiSEyG/RpNsKXGHFZBOCnvjs4hTQKg9QEzLvoqBZ/e3vUAsswMFLvP eTTMRvgfNz2TSeOR1F5tNrMTnilAuBUZ8sCUw4HwtNN2KAnUNKtuGD174U00z7pH qKCfZffm34Vb7niEZsVn2MhvbXwdUgWmEF1yqwApXTfnXsDTqWLakhMUHExIMozo 8jIewD30v6Daj+biPGxnmikRl9XfzgCN5nO11lx68rwur4q2KMYvSRdMVecipa6U grSgXebFoQgdnj+2CN/0Z0pMqHeXpgMYzpG04o30/SjXgF4KRD6nDLZamJwwVHDj Iivn5EyJeOt83BKSAtHm6tRqIbZ1abVwHoztxPDgl0nnuEtRv4VMGECOtLlGkHkx lV2DdLd4UyahF3gPp6xvbnmhk6yWH4xMN0zwImSI4Lt7+ncRoZ6dy2i3HxrHNyu6 8zMKdZQDnMMoxcdqSxy5nXezf/x6e2MVReQiWLbSzpD1WU6OD0BrfGMe+3sFXSde lsFgkAigdJ58t2vZ+gwb =TXhl -----END PGP SIGNATURE----- Merge tag 'iio-for-3.12d' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next Jonathan writes: Fourth round of IIO new drivers, functionality and cleanups for the 3.13 cycle. New Drivers * cm36651 combined RGB light and proximity sensor. Core improvements * Some more fixes and cleanups related to buffers. These include the second half of a series which went is as fixes. The basis for delaying until the next merge window is that some are too invasive for this late in a cycle and others only effect code paths current unused in the mainline tree. In this case we have: * protecting against concurrent userspace access * fixing a memory leak if a device goes away * avoiding always reallocating the buffer whether or not it has changed (a bug fix, but one with no functional changes other than a small speed improvement.) * Add reference counting for buffers to ensure they hang around if open from userspace or in kernel when the device is forcefully removed. * Return -ENODEV for buffer access operations when the device has gone away. * Add proper locking for iio_update_buffers (currently we only have one buffer per device in mainline, but an input bridge driver is under development which would make this bug 'real'.) * Wake up anyone waiting on a buffer if the device is unregistered. A subsequent read will fail, notifying userspace that the device is no longer there rather than having it wait possibly for ever. * Move the iio_sw_preenable functionality into the core. This avoids drivers having to 'know' about how the buffers are implemented and is called by almost all drivers anyway. Those that don't call it are not harmed by it being called. * New registration approach for information (i.e. sysfs attributes) about events. Much more generic and now similar to how the equivalent is handled for channel information. The events infrastructure had been left behind by other changes so this brings it back in line. * Using the new events registration approach, add a hysterisis event_info element and apply this to those drivers with this property. * A little unitialized variable bug in the generic_buffer.c example. * Factor out the code for freeing lists of IIO Device attributes to avoid some repitition. Driver cleanups * At91 driver gains touch screen support and some related fixes. * Follow up series of patches removing the now redundant iio_sw_buffer_preenable calls. * Lots of conversions to the new event registration methods. * Another round of hmc5843 cleanups as that driver moves towards graduating from staging. * Make some SoC drivers buildable if COMPILE_TEST is used. Follow up fixes for a few bits and bobs that revealed. * Add explicit includes of linux/of.h to those drivers making us of linux/of.h
This commit is contained in:
commit
2ef9d838e4
57 changed files with 2913 additions and 1246 deletions
|
@ -537,6 +537,62 @@ Description:
|
|||
value is in raw device units or in processed units (as _raw
|
||||
and _input do on sysfs direct channel read attributes).
|
||||
|
||||
What: /sys/.../events/in_accel_x_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_accel_x_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_accel_x_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_accel_y_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_accel_y_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_accel_y_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_accel_z_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_accel_z_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_accel_z_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_anglvel_x_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_anglvel_x_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_anglvel_x_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_anglvel_y_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_anglvel_y_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_anglvel_y_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_anglvel_z_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_anglvel_z_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_anglvel_z_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_magn_x_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_magn_x_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_magn_x_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_magn_y_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_magn_y_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_magn_y_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_magn_z_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_magn_z_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_magn_z_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_voltageY_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_voltageY_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_voltageY_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_tempY_thresh_rising_hysteresis
|
||||
What: /sys/.../events/in_tempY_thresh_falling_hysteresis
|
||||
What: /sys/.../events/in_tempY_thresh_either_hysteresis
|
||||
What: /sys/.../events/in_illuminance0_thresh_falling_hysteresis
|
||||
what: /sys/.../events/in_illuminance0_thresh_rising_hysteresis
|
||||
what: /sys/.../events/in_illuminance0_thresh_either_hysteresis
|
||||
what: /sys/.../events/in_proximity0_thresh_falling_hysteresis
|
||||
what: /sys/.../events/in_proximity0_thresh_rising_hysteresis
|
||||
what: /sys/.../events/in_proximity0_thresh_either_hysteresis
|
||||
KernelVersion: 3.13
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
Specifies the hysteresis of threshold that the device is comparing
|
||||
against for the events enabled by
|
||||
<type>Y[_name]_thresh[_(rising|falling)]_hysteresis.
|
||||
If separate attributes exist for the two directions, but
|
||||
direction is not specified for this attribute, then a single
|
||||
hysteresis value applies to both directions.
|
||||
For falling events the hysteresis is added to the _value attribute for
|
||||
this event to get the upper threshold for when the event goes back to
|
||||
normal, for rising events the hysteresis is subtracted from the _value
|
||||
attribute. E.g. if in_voltage0_raw_thresh_rising_value is set to 1200
|
||||
and in_voltage0_raw_thresh_rising_hysteresis is set to 50. The event
|
||||
will get activated once in_voltage0_raw goes above 1200 and will become
|
||||
deactived again once the value falls below 1150.
|
||||
|
||||
What: /sys/.../events/in_accel_x_raw_roc_rising_value
|
||||
What: /sys/.../events/in_accel_x_raw_roc_falling_value
|
||||
What: /sys/.../events/in_accel_y_raw_roc_rising_value
|
||||
|
|
|
@ -7,7 +7,6 @@ Required properties:
|
|||
- interrupts: Should contain the IRQ line for the ADC
|
||||
- atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
|
||||
device
|
||||
- atmel,adc-num-channels: Number of channels available in the ADC
|
||||
- atmel,adc-startup-time: Startup Time of the ADC in microseconds as
|
||||
defined in the datasheet
|
||||
- atmel,adc-vref: Reference voltage in millivolts for the conversions
|
||||
|
@ -24,6 +23,13 @@ Optional properties:
|
|||
resolution will be used.
|
||||
- atmel,adc-sleep-mode: Boolean to enable sleep mode when no conversion
|
||||
- atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
|
||||
- atmel,adc-ts-wires: Number of touch screen wires. Should be 4 or 5. If this
|
||||
value is set, then adc driver will enable touch screen
|
||||
support.
|
||||
NOTE: when adc touch screen enabled, the adc hardware trigger will be
|
||||
disabled. Since touch screen will occupied the trigger register.
|
||||
- atmel,adc-ts-pressure-threshold: a pressure threshold for touchscreen. It
|
||||
make touch detect more precision.
|
||||
|
||||
Optional trigger Nodes:
|
||||
- Required properties:
|
||||
|
|
26
Documentation/devicetree/bindings/iio/light/cm36651.txt
Normal file
26
Documentation/devicetree/bindings/iio/light/cm36651.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
* Capella CM36651 I2C Proximity and Color Light sensor
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "capella,cm36651"
|
||||
- reg: the I2C address of the device
|
||||
- interrupts: interrupt-specifier for the sole interrupt
|
||||
generated by the device
|
||||
- vled-supply: regulator for the IR LED. IR_LED is a part
|
||||
of the cm36651 for proximity detection.
|
||||
As covered in ../../regulator/regulator.txt
|
||||
|
||||
Example:
|
||||
|
||||
i2c_cm36651: i2c-gpio {
|
||||
/* ... */
|
||||
|
||||
cm36651@18 {
|
||||
compatible = "capella,cm36651";
|
||||
reg = <0x18>;
|
||||
interrupt-parent = <&gpx0>;
|
||||
interrupts = <2 0>;
|
||||
vled-supply = <&ps_als_reg>;
|
||||
};
|
||||
|
||||
/* ... */
|
||||
};
|
|
@ -15,6 +15,7 @@ atmel Atmel Corporation
|
|||
avago Avago Technologies
|
||||
bosch Bosch Sensortec GmbH
|
||||
brcm Broadcom Corporation
|
||||
capella Capella Microsystems, Inc
|
||||
cavium Cavium, Inc.
|
||||
chrp Common Hardware Reference Platform
|
||||
cirrus Cirrus Logic, Inc.
|
||||
|
|
|
@ -60,14 +60,48 @@
|
|||
#define AT91_ADC_IER 0x24 /* Interrupt Enable Register */
|
||||
#define AT91_ADC_IDR 0x28 /* Interrupt Disable Register */
|
||||
#define AT91_ADC_IMR 0x2C /* Interrupt Mask Register */
|
||||
#define AT91_ADC_IER_PEN (1 << 29)
|
||||
#define AT91_ADC_IER_NOPEN (1 << 30)
|
||||
#define AT91_ADC_IER_XRDY (1 << 20)
|
||||
#define AT91_ADC_IER_YRDY (1 << 21)
|
||||
#define AT91_ADC_IER_PRDY (1 << 22)
|
||||
#define AT91_ADC_ISR_PENS (1 << 31)
|
||||
|
||||
#define AT91_ADC_CHR(n) (0x30 + ((n) * 4)) /* Channel Data Register N */
|
||||
#define AT91_ADC_DATA (0x3ff)
|
||||
|
||||
#define AT91_ADC_CDR0_9X5 (0x50) /* Channel Data Register 0 for 9X5 */
|
||||
|
||||
#define AT91_ADC_ACR 0x94 /* Analog Control Register */
|
||||
#define AT91_ADC_ACR_PENDETSENS (0x3 << 0) /* pull-up resistor */
|
||||
|
||||
#define AT91_ADC_TSMR 0xB0
|
||||
#define AT91_ADC_TSMR_TSMODE (3 << 0) /* Touch Screen Mode */
|
||||
#define AT91_ADC_TSMR_TSMODE_NONE (0 << 0)
|
||||
#define AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS (1 << 0)
|
||||
#define AT91_ADC_TSMR_TSMODE_4WIRE_PRESS (2 << 0)
|
||||
#define AT91_ADC_TSMR_TSMODE_5WIRE (3 << 0)
|
||||
#define AT91_ADC_TSMR_TSAV (3 << 4) /* Averages samples */
|
||||
#define AT91_ADC_TSMR_TSAV_(x) ((x) << 4)
|
||||
#define AT91_ADC_TSMR_SCTIM (0x0f << 16) /* Switch closure time */
|
||||
#define AT91_ADC_TSMR_PENDBC (0x0f << 28) /* Pen Debounce time */
|
||||
#define AT91_ADC_TSMR_PENDBC_(x) ((x) << 28)
|
||||
#define AT91_ADC_TSMR_NOTSDMA (1 << 22) /* No Touchscreen DMA */
|
||||
#define AT91_ADC_TSMR_PENDET_DIS (0 << 24) /* Pen contact detection disable */
|
||||
#define AT91_ADC_TSMR_PENDET_ENA (1 << 24) /* Pen contact detection enable */
|
||||
|
||||
#define AT91_ADC_TSXPOSR 0xB4
|
||||
#define AT91_ADC_TSYPOSR 0xB8
|
||||
#define AT91_ADC_TSPRESSR 0xBC
|
||||
|
||||
#define AT91_ADC_TRGR_9260 AT91_ADC_MR
|
||||
#define AT91_ADC_TRGR_9G45 0x08
|
||||
#define AT91_ADC_TRGR_9X5 0xC0
|
||||
|
||||
/* Trigger Register bit field */
|
||||
#define AT91_ADC_TRGR_TRGPER (0xffff << 16)
|
||||
#define AT91_ADC_TRGR_TRGPER_(x) ((x) << 16)
|
||||
#define AT91_ADC_TRGR_TRGMOD (0x7 << 0)
|
||||
#define AT91_ADC_TRGR_MOD_PERIOD_TRIG (5 << 0)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,16 +32,7 @@ int st_accel_trig_set_state(struct iio_trigger *trig, bool state)
|
|||
|
||||
static int st_accel_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = st_sensors_set_enable(indio_dev, true);
|
||||
if (err < 0)
|
||||
goto st_accel_set_enable_error;
|
||||
|
||||
err = iio_sw_buffer_preenable(indio_dev);
|
||||
|
||||
st_accel_set_enable_error:
|
||||
return err;
|
||||
return st_sensors_set_enable(indio_dev, true);
|
||||
}
|
||||
|
||||
static int st_accel_buffer_postenable(struct iio_dev *indio_dev)
|
||||
|
|
|
@ -61,17 +61,7 @@ static int ad7266_powerdown(struct ad7266_state *st)
|
|||
static int ad7266_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7266_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = ad7266_wakeup(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_sw_buffer_preenable(indio_dev);
|
||||
if (ret)
|
||||
ad7266_powerdown(st);
|
||||
|
||||
return ret;
|
||||
return ad7266_wakeup(st);
|
||||
}
|
||||
|
||||
static int ad7266_postdisable(struct iio_dev *indio_dev)
|
||||
|
|
|
@ -78,11 +78,6 @@ enum ad7887_supported_device_ids {
|
|||
static int ad7887_ring_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ad7887_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = iio_sw_buffer_preenable(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* We know this is a single long so can 'cheat' */
|
||||
switch (*indio_dev->active_scan_mask) {
|
||||
|
|
|
@ -397,7 +397,6 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
|
|||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = {
|
||||
.preenable = &iio_sw_buffer_preenable,
|
||||
.postenable = &ad_sd_buffer_postenable,
|
||||
.predisable = &iio_triggered_buffer_predisable,
|
||||
.postdisable = &ad_sd_buffer_postdisable,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -39,10 +40,36 @@
|
|||
#define at91_adc_writel(st, reg, val) \
|
||||
(writel_relaxed(val, st->reg_base + reg))
|
||||
|
||||
#define DRIVER_NAME "at91_adc"
|
||||
#define MAX_POS_BITS 12
|
||||
|
||||
#define TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */
|
||||
#define TOUCH_PEN_DETECT_DEBOUNCE_US 200
|
||||
|
||||
struct at91_adc_caps {
|
||||
bool has_ts; /* Support touch screen */
|
||||
bool has_tsmr; /* only at91sam9x5, sama5d3 have TSMR reg */
|
||||
/*
|
||||
* Numbers of sampling data will be averaged. Can be 0~3.
|
||||
* Hardware can average (2 ^ ts_filter_average) sample data.
|
||||
*/
|
||||
u8 ts_filter_average;
|
||||
/* Pen Detection input pull-up resistor, can be 0~3 */
|
||||
u8 ts_pen_detect_sensitivity;
|
||||
|
||||
/* startup time calculate function */
|
||||
u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz);
|
||||
|
||||
u8 num_channels;
|
||||
struct at91_adc_reg_desc registers;
|
||||
};
|
||||
|
||||
enum atmel_adc_ts_type {
|
||||
ATMEL_ADC_TOUCHSCREEN_NONE = 0,
|
||||
ATMEL_ADC_TOUCHSCREEN_4WIRE = 4,
|
||||
ATMEL_ADC_TOUCHSCREEN_5WIRE = 5,
|
||||
};
|
||||
|
||||
struct at91_adc_state {
|
||||
struct clk *adc_clk;
|
||||
u16 *buffer;
|
||||
|
@ -67,6 +94,26 @@ struct at91_adc_state {
|
|||
bool low_res; /* the resolution corresponds to the lowest one */
|
||||
wait_queue_head_t wq_data_avail;
|
||||
struct at91_adc_caps *caps;
|
||||
|
||||
/*
|
||||
* Following ADC channels are shared by touchscreen:
|
||||
*
|
||||
* CH0 -- Touch screen XP/UL
|
||||
* CH1 -- Touch screen XM/UR
|
||||
* CH2 -- Touch screen YP/LL
|
||||
* CH3 -- Touch screen YM/Sense
|
||||
* CH4 -- Touch screen LR(5-wire only)
|
||||
*
|
||||
* The bitfields below represents the reserved channel in the
|
||||
* touchscreen mode.
|
||||
*/
|
||||
#define CHAN_MASK_TOUCHSCREEN_4WIRE (0xf << 0)
|
||||
#define CHAN_MASK_TOUCHSCREEN_5WIRE (0x1f << 0)
|
||||
enum atmel_adc_ts_type touchscreen_type;
|
||||
struct input_dev *ts_input;
|
||||
|
||||
u16 ts_sample_period_val;
|
||||
u32 ts_pressure_threshold;
|
||||
};
|
||||
|
||||
static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
|
||||
|
@ -95,14 +142,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
|
||||
/* Handler for classic adc channel eoc trigger */
|
||||
void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
|
||||
{
|
||||
struct iio_dev *idev = private;
|
||||
struct at91_adc_state *st = iio_priv(idev);
|
||||
u32 status = at91_adc_readl(st, st->registers->status_register);
|
||||
|
||||
if (!(status & st->registers->drdy_mask))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (iio_buffer_enabled(idev)) {
|
||||
disable_irq_nosync(irq);
|
||||
|
@ -112,6 +155,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
|
|||
st->done = true;
|
||||
wake_up_interruptible(&st->wq_data_avail);
|
||||
}
|
||||
}
|
||||
|
||||
static int at91_ts_sample(struct at91_adc_state *st)
|
||||
{
|
||||
unsigned int xscale, yscale, reg, z1, z2;
|
||||
unsigned int x, y, pres, xpos, ypos;
|
||||
unsigned int rxp = 1;
|
||||
unsigned int factor = 1000;
|
||||
struct iio_dev *idev = iio_priv_to_dev(st);
|
||||
|
||||
unsigned int xyz_mask_bits = st->res;
|
||||
unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
|
||||
|
||||
/* calculate position */
|
||||
/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
|
||||
reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
|
||||
xpos = reg & xyz_mask;
|
||||
x = (xpos << MAX_POS_BITS) - xpos;
|
||||
xscale = (reg >> 16) & xyz_mask;
|
||||
if (xscale == 0) {
|
||||
dev_err(&idev->dev, "Error: xscale == 0!\n");
|
||||
return -1;
|
||||
}
|
||||
x /= xscale;
|
||||
|
||||
/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
|
||||
reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
|
||||
ypos = reg & xyz_mask;
|
||||
y = (ypos << MAX_POS_BITS) - ypos;
|
||||
yscale = (reg >> 16) & xyz_mask;
|
||||
if (yscale == 0) {
|
||||
dev_err(&idev->dev, "Error: yscale == 0!\n");
|
||||
return -1;
|
||||
}
|
||||
y /= yscale;
|
||||
|
||||
/* calculate the pressure */
|
||||
reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
|
||||
z1 = reg & xyz_mask;
|
||||
z2 = (reg >> 16) & xyz_mask;
|
||||
|
||||
if (z1 != 0)
|
||||
pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
|
||||
/ factor;
|
||||
else
|
||||
pres = st->ts_pressure_threshold; /* no pen contacted */
|
||||
|
||||
dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
|
||||
xpos, xscale, ypos, yscale, z1, z2, pres);
|
||||
|
||||
if (pres < st->ts_pressure_threshold) {
|
||||
dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
|
||||
x, y, pres / factor);
|
||||
input_report_abs(st->ts_input, ABS_X, x);
|
||||
input_report_abs(st->ts_input, ABS_Y, y);
|
||||
input_report_abs(st->ts_input, ABS_PRESSURE, pres);
|
||||
input_report_key(st->ts_input, BTN_TOUCH, 1);
|
||||
input_sync(st->ts_input);
|
||||
} else {
|
||||
dev_dbg(&idev->dev, "pressure too low: not reporting\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t at91_adc_interrupt(int irq, void *private)
|
||||
{
|
||||
struct iio_dev *idev = private;
|
||||
struct at91_adc_state *st = iio_priv(idev);
|
||||
u32 status = at91_adc_readl(st, st->registers->status_register);
|
||||
const uint32_t ts_data_irq_mask =
|
||||
AT91_ADC_IER_XRDY |
|
||||
AT91_ADC_IER_YRDY |
|
||||
AT91_ADC_IER_PRDY;
|
||||
|
||||
if (status & st->registers->drdy_mask)
|
||||
handle_adc_eoc_trigger(irq, idev);
|
||||
|
||||
if (status & AT91_ADC_IER_PEN) {
|
||||
at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
|
||||
at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
|
||||
ts_data_irq_mask);
|
||||
/* Set up period trigger for sampling */
|
||||
at91_adc_writel(st, st->registers->trigger_register,
|
||||
AT91_ADC_TRGR_MOD_PERIOD_TRIG |
|
||||
AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
|
||||
} else if (status & AT91_ADC_IER_NOPEN) {
|
||||
at91_adc_writel(st, st->registers->trigger_register, 0);
|
||||
at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
|
||||
ts_data_irq_mask);
|
||||
at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
|
||||
|
||||
input_report_key(st->ts_input, BTN_TOUCH, 0);
|
||||
input_sync(st->ts_input);
|
||||
} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
|
||||
/* Now all touchscreen data is ready */
|
||||
|
||||
if (status & AT91_ADC_ISR_PENS) {
|
||||
/* validate data by pen contact */
|
||||
at91_ts_sample(st);
|
||||
} else {
|
||||
/* triggered by event that is no pen contact, just read
|
||||
* them to clean the interrupt and discard all.
|
||||
*/
|
||||
at91_adc_readl(st, AT91_ADC_TSXPOSR);
|
||||
at91_adc_readl(st, AT91_ADC_TSYPOSR);
|
||||
at91_adc_readl(st, AT91_ADC_TSPRESSR);
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -121,6 +273,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
|
|||
struct at91_adc_state *st = iio_priv(idev);
|
||||
struct iio_chan_spec *chan_array, *timestamp;
|
||||
int bit, idx = 0;
|
||||
unsigned long rsvd_mask = 0;
|
||||
|
||||
/* If touchscreen is enable, then reserve the adc channels */
|
||||
if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
|
||||
rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
|
||||
else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
|
||||
rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
|
||||
|
||||
/* set up the channel mask to reserve touchscreen channels */
|
||||
st->channels_mask &= ~rsvd_mask;
|
||||
|
||||
idev->num_channels = bitmap_weight(&st->channels_mask,
|
||||
st->num_channels) + 1;
|
||||
|
@ -428,8 +590,80 @@ static int at91_adc_of_get_resolution(struct at91_adc_state *st,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static u32 calc_startup_ticks_9260(u8 startup_time, u32 adc_clk_khz)
|
||||
{
|
||||
/*
|
||||
* Number of ticks needed to cover the startup time of the ADC
|
||||
* as defined in the electrical characteristics of the board,
|
||||
* divided by 8. The formula thus is :
|
||||
* Startup Time = (ticks + 1) * 8 / ADC Clock
|
||||
*/
|
||||
return round_up((startup_time * adc_clk_khz / 1000) - 1, 8) / 8;
|
||||
}
|
||||
|
||||
static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz)
|
||||
{
|
||||
/*
|
||||
* For sama5d3x and at91sam9x5, the formula changes to:
|
||||
* Startup Time = <lookup_table_value> / ADC Clock
|
||||
*/
|
||||
const int startup_lookup[] = {
|
||||
0 , 8 , 16 , 24 ,
|
||||
64 , 80 , 96 , 112,
|
||||
512, 576, 640, 704,
|
||||
768, 832, 896, 960
|
||||
};
|
||||
int i, size = ARRAY_SIZE(startup_lookup);
|
||||
unsigned int ticks;
|
||||
|
||||
ticks = startup_time * adc_clk_khz / 1000;
|
||||
for (i = 0; i < size; i++)
|
||||
if (ticks < startup_lookup[i])
|
||||
break;
|
||||
|
||||
ticks = i;
|
||||
if (ticks == size)
|
||||
/* Reach the end of lookup table */
|
||||
ticks = size - 1;
|
||||
|
||||
return ticks;
|
||||
}
|
||||
|
||||
static const struct of_device_id at91_adc_dt_ids[];
|
||||
|
||||
static int at91_adc_probe_dt_ts(struct device_node *node,
|
||||
struct at91_adc_state *st, struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
u32 prop;
|
||||
|
||||
ret = of_property_read_u32(node, "atmel,adc-ts-wires", &prop);
|
||||
if (ret) {
|
||||
dev_info(dev, "ADC Touch screen is disabled.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (prop) {
|
||||
case 4:
|
||||
case 5:
|
||||
st->touchscreen_type = prop;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Unsupported number of touchscreen wires (%d). Should be 4 or 5.\n", prop);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
prop = 0;
|
||||
of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop);
|
||||
st->ts_pressure_threshold = prop;
|
||||
if (st->ts_pressure_threshold) {
|
||||
return 0;
|
||||
} else {
|
||||
dev_err(dev, "Invalid pressure threshold for the touchscreen\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int at91_adc_probe_dt(struct at91_adc_state *st,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
|
@ -454,13 +688,6 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
|
|||
}
|
||||
st->channels_mask = prop;
|
||||
|
||||
if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
|
||||
dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
st->num_channels = prop;
|
||||
|
||||
st->sleep_mode = of_property_read_bool(node, "atmel,adc-sleep-mode");
|
||||
|
||||
if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
|
||||
|
@ -486,6 +713,7 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
|
|||
goto error_ret;
|
||||
|
||||
st->registers = &st->caps->registers;
|
||||
st->num_channels = st->caps->num_channels;
|
||||
st->trigger_number = of_get_child_count(node);
|
||||
st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
|
||||
sizeof(struct at91_adc_trigger),
|
||||
|
@ -517,6 +745,12 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
|
|||
i++;
|
||||
}
|
||||
|
||||
/* Check if touchscreen is supported. */
|
||||
if (st->caps->has_ts)
|
||||
return at91_adc_probe_dt_ts(node, st, &idev->dev);
|
||||
else
|
||||
dev_info(&idev->dev, "not support touchscreen in the adc compatible string.\n");
|
||||
|
||||
return 0;
|
||||
|
||||
error_ret:
|
||||
|
@ -548,6 +782,114 @@ static const struct iio_info at91_adc_info = {
|
|||
.read_raw = &at91_adc_read_raw,
|
||||
};
|
||||
|
||||
/* Touchscreen related functions */
|
||||
static int atmel_ts_open(struct input_dev *dev)
|
||||
{
|
||||
struct at91_adc_state *st = input_get_drvdata(dev);
|
||||
|
||||
at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmel_ts_close(struct input_dev *dev)
|
||||
{
|
||||
struct at91_adc_state *st = input_get_drvdata(dev);
|
||||
|
||||
at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
|
||||
}
|
||||
|
||||
static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
|
||||
{
|
||||
u32 reg = 0, pendbc;
|
||||
int i = 0;
|
||||
|
||||
if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
|
||||
reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
|
||||
else
|
||||
reg = AT91_ADC_TSMR_TSMODE_5WIRE;
|
||||
|
||||
/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
|
||||
* pen detect noise.
|
||||
* The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
|
||||
*/
|
||||
pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1);
|
||||
|
||||
while (pendbc >> ++i)
|
||||
; /* Empty! Find the shift offset */
|
||||
if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
|
||||
pendbc = i;
|
||||
else
|
||||
pendbc = i - 1;
|
||||
|
||||
if (st->caps->has_tsmr) {
|
||||
reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
|
||||
& AT91_ADC_TSMR_TSAV;
|
||||
reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
|
||||
reg |= AT91_ADC_TSMR_NOTSDMA;
|
||||
reg |= AT91_ADC_TSMR_PENDET_ENA;
|
||||
reg |= 0x03 << 8; /* TSFREQ, need bigger than TSAV */
|
||||
|
||||
at91_adc_writel(st, AT91_ADC_TSMR, reg);
|
||||
} else {
|
||||
/* TODO: for 9g45 which has no TSMR */
|
||||
}
|
||||
|
||||
/* Change adc internal resistor value for better pen detection,
|
||||
* default value is 100 kOhm.
|
||||
* 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
|
||||
* option only available on ES2 and higher
|
||||
*/
|
||||
at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity
|
||||
& AT91_ADC_ACR_PENDETSENS);
|
||||
|
||||
/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
|
||||
st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US *
|
||||
adc_clk_khz / 1000) - 1, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91_ts_register(struct at91_adc_state *st,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct input_dev *input;
|
||||
struct iio_dev *idev = iio_priv_to_dev(st);
|
||||
int ret;
|
||||
|
||||
input = input_allocate_device();
|
||||
if (!input) {
|
||||
dev_err(&idev->dev, "Failed to allocate TS device!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input->name = DRIVER_NAME;
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->dev.parent = &pdev->dev;
|
||||
input->open = atmel_ts_open;
|
||||
input->close = atmel_ts_close;
|
||||
|
||||
__set_bit(EV_ABS, input->evbit);
|
||||
__set_bit(EV_KEY, input->evbit);
|
||||
__set_bit(BTN_TOUCH, input->keybit);
|
||||
input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
|
||||
input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
|
||||
input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
|
||||
|
||||
st->ts_input = input;
|
||||
input_set_drvdata(input, st);
|
||||
|
||||
ret = input_register_device(input);
|
||||
if (ret)
|
||||
input_free_device(st->ts_input);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void at91_ts_unregister(struct at91_adc_state *st)
|
||||
{
|
||||
input_unregister_device(st->ts_input);
|
||||
}
|
||||
|
||||
static int at91_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
unsigned int prsc, mstrclk, ticks, adc_clk, adc_clk_khz, shtim;
|
||||
|
@ -599,7 +941,7 @@ static int at91_adc_probe(struct platform_device *pdev)
|
|||
at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
|
||||
at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
|
||||
ret = request_irq(st->irq,
|
||||
at91_adc_eoc_trigger,
|
||||
at91_adc_interrupt,
|
||||
0,
|
||||
pdev->dev.driver->name,
|
||||
idev);
|
||||
|
@ -644,6 +986,10 @@ static int at91_adc_probe(struct platform_device *pdev)
|
|||
mstrclk = clk_get_rate(st->clk);
|
||||
adc_clk = clk_get_rate(st->adc_clk);
|
||||
adc_clk_khz = adc_clk / 1000;
|
||||
|
||||
dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
|
||||
mstrclk, adc_clk);
|
||||
|
||||
prsc = (mstrclk / (2 * adc_clk)) - 1;
|
||||
|
||||
if (!st->startup_time) {
|
||||
|
@ -651,14 +997,8 @@ static int at91_adc_probe(struct platform_device *pdev)
|
|||
ret = -EINVAL;
|
||||
goto error_disable_adc_clk;
|
||||
}
|
||||
ticks = (*st->caps->calc_startup_ticks)(st->startup_time, adc_clk_khz);
|
||||
|
||||
/*
|
||||
* Number of ticks needed to cover the startup time of the ADC as
|
||||
* defined in the electrical characteristics of the board, divided by 8.
|
||||
* The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
|
||||
*/
|
||||
ticks = round_up((st->startup_time * adc_clk_khz /
|
||||
1000) - 1, 8) / 8;
|
||||
/*
|
||||
* a minimal Sample and Hold Time is necessary for the ADC to guarantee
|
||||
* the best converted final value between two channels selection
|
||||
|
@ -686,30 +1026,52 @@ static int at91_adc_probe(struct platform_device *pdev)
|
|||
init_waitqueue_head(&st->wq_data_avail);
|
||||
mutex_init(&st->lock);
|
||||
|
||||
ret = at91_adc_buffer_init(idev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
|
||||
goto error_disable_adc_clk;
|
||||
}
|
||||
/*
|
||||
* Since touch screen will set trigger register as period trigger. So
|
||||
* when touch screen is enabled, then we have to disable hardware
|
||||
* trigger for classic adc.
|
||||
*/
|
||||
if (!st->touchscreen_type) {
|
||||
ret = at91_adc_buffer_init(idev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
|
||||
goto error_disable_adc_clk;
|
||||
}
|
||||
|
||||
ret = at91_adc_trigger_init(idev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
|
||||
goto error_unregister_buffer;
|
||||
ret = at91_adc_trigger_init(idev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
|
||||
at91_adc_buffer_remove(idev);
|
||||
goto error_disable_adc_clk;
|
||||
}
|
||||
} else {
|
||||
if (!st->caps->has_tsmr) {
|
||||
dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
|
||||
goto error_disable_adc_clk;
|
||||
}
|
||||
|
||||
ret = at91_ts_register(st, pdev);
|
||||
if (ret)
|
||||
goto error_disable_adc_clk;
|
||||
|
||||
at91_ts_hw_init(st, adc_clk_khz);
|
||||
}
|
||||
|
||||
ret = iio_device_register(idev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Couldn't register the device.\n");
|
||||
goto error_remove_triggers;
|
||||
goto error_iio_device_register;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_remove_triggers:
|
||||
at91_adc_trigger_remove(idev);
|
||||
error_unregister_buffer:
|
||||
at91_adc_buffer_remove(idev);
|
||||
error_iio_device_register:
|
||||
if (!st->touchscreen_type) {
|
||||
at91_adc_trigger_remove(idev);
|
||||
at91_adc_buffer_remove(idev);
|
||||
} else {
|
||||
at91_ts_unregister(st);
|
||||
}
|
||||
error_disable_adc_clk:
|
||||
clk_disable_unprepare(st->adc_clk);
|
||||
error_disable_clk:
|
||||
|
@ -725,8 +1087,12 @@ static int at91_adc_remove(struct platform_device *pdev)
|
|||
struct at91_adc_state *st = iio_priv(idev);
|
||||
|
||||
iio_device_unregister(idev);
|
||||
at91_adc_trigger_remove(idev);
|
||||
at91_adc_buffer_remove(idev);
|
||||
if (!st->touchscreen_type) {
|
||||
at91_adc_trigger_remove(idev);
|
||||
at91_adc_buffer_remove(idev);
|
||||
} else {
|
||||
at91_ts_unregister(st);
|
||||
}
|
||||
clk_disable_unprepare(st->adc_clk);
|
||||
clk_disable_unprepare(st->clk);
|
||||
free_irq(st->irq, idev);
|
||||
|
@ -736,6 +1102,8 @@ static int at91_adc_remove(struct platform_device *pdev)
|
|||
|
||||
#ifdef CONFIG_OF
|
||||
static struct at91_adc_caps at91sam9260_caps = {
|
||||
.calc_startup_ticks = calc_startup_ticks_9260,
|
||||
.num_channels = 4,
|
||||
.registers = {
|
||||
.channel_base = AT91_ADC_CHR(0),
|
||||
.drdy_mask = AT91_ADC_DRDY,
|
||||
|
@ -747,6 +1115,9 @@ static struct at91_adc_caps at91sam9260_caps = {
|
|||
};
|
||||
|
||||
static struct at91_adc_caps at91sam9g45_caps = {
|
||||
.has_ts = true,
|
||||
.calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */
|
||||
.num_channels = 8,
|
||||
.registers = {
|
||||
.channel_base = AT91_ADC_CHR(0),
|
||||
.drdy_mask = AT91_ADC_DRDY,
|
||||
|
@ -758,6 +1129,12 @@ static struct at91_adc_caps at91sam9g45_caps = {
|
|||
};
|
||||
|
||||
static struct at91_adc_caps at91sam9x5_caps = {
|
||||
.has_ts = true,
|
||||
.has_tsmr = true,
|
||||
.ts_filter_average = 3,
|
||||
.ts_pen_detect_sensitivity = 2,
|
||||
.calc_startup_ticks = calc_startup_ticks_9x5,
|
||||
.num_channels = 12,
|
||||
.registers = {
|
||||
.channel_base = AT91_ADC_CDR0_9X5,
|
||||
.drdy_mask = AT91_ADC_SR_DRDY_9X5,
|
||||
|
@ -782,7 +1159,7 @@ static struct platform_driver at91_adc_driver = {
|
|||
.probe = at91_adc_probe,
|
||||
.remove = at91_adc_remove,
|
||||
.driver = {
|
||||
.name = "at91_adc",
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = of_match_ptr(at91_adc_dt_ids),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -422,11 +422,21 @@ static const enum max1363_modes max1363_mode_list[] = {
|
|||
d0m1to2m3, d1m0to3m2,
|
||||
};
|
||||
|
||||
#define MAX1363_EV_M \
|
||||
(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \
|
||||
| IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
|
||||
static const struct iio_event_spec max1363_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
#define MAX1363_CHAN_U(num, addr, si, bits, evmask) \
|
||||
#define MAX1363_CHAN_U(num, addr, si, bits, ev_spec, num_ev_spec) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
|
@ -442,11 +452,12 @@ static const enum max1363_modes max1363_mode_list[] = {
|
|||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
.scan_index = si, \
|
||||
.event_mask = evmask, \
|
||||
.event_spec = ev_spec, \
|
||||
.num_event_specs = num_ev_spec, \
|
||||
}
|
||||
|
||||
/* bipolar channel */
|
||||
#define MAX1363_CHAN_B(num, num2, addr, si, bits, evmask) \
|
||||
#define MAX1363_CHAN_B(num, num2, addr, si, bits, ev_spec, num_ev_spec) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.differential = 1, \
|
||||
|
@ -464,28 +475,32 @@ static const enum max1363_modes max1363_mode_list[] = {
|
|||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
.scan_index = si, \
|
||||
.event_mask = evmask, \
|
||||
.event_spec = ev_spec, \
|
||||
.num_event_specs = num_ev_spec, \
|
||||
}
|
||||
|
||||
#define MAX1363_4X_CHANS(bits, em) { \
|
||||
MAX1363_CHAN_U(0, _s0, 0, bits, em), \
|
||||
MAX1363_CHAN_U(1, _s1, 1, bits, em), \
|
||||
MAX1363_CHAN_U(2, _s2, 2, bits, em), \
|
||||
MAX1363_CHAN_U(3, _s3, 3, bits, em), \
|
||||
MAX1363_CHAN_B(0, 1, d0m1, 4, bits, em), \
|
||||
MAX1363_CHAN_B(2, 3, d2m3, 5, bits, em), \
|
||||
MAX1363_CHAN_B(1, 0, d1m0, 6, bits, em), \
|
||||
MAX1363_CHAN_B(3, 2, d3m2, 7, bits, em), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8) \
|
||||
#define MAX1363_4X_CHANS(bits, ev_spec, num_ev_spec) { \
|
||||
MAX1363_CHAN_U(0, _s0, 0, bits, ev_spec, num_ev_spec), \
|
||||
MAX1363_CHAN_U(1, _s1, 1, bits, ev_spec, num_ev_spec), \
|
||||
MAX1363_CHAN_U(2, _s2, 2, bits, ev_spec, num_ev_spec), \
|
||||
MAX1363_CHAN_U(3, _s3, 3, bits, ev_spec, num_ev_spec), \
|
||||
MAX1363_CHAN_B(0, 1, d0m1, 4, bits, ev_spec, num_ev_spec), \
|
||||
MAX1363_CHAN_B(2, 3, d2m3, 5, bits, ev_spec, num_ev_spec), \
|
||||
MAX1363_CHAN_B(1, 0, d1m0, 6, bits, ev_spec, num_ev_spec), \
|
||||
MAX1363_CHAN_B(3, 2, d3m2, 7, bits, ev_spec, num_ev_spec), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8) \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec max1036_channels[] = MAX1363_4X_CHANS(8, 0);
|
||||
static const struct iio_chan_spec max1136_channels[] = MAX1363_4X_CHANS(10, 0);
|
||||
static const struct iio_chan_spec max1236_channels[] = MAX1363_4X_CHANS(12, 0);
|
||||
static const struct iio_chan_spec max1036_channels[] =
|
||||
MAX1363_4X_CHANS(8, NULL, 0);
|
||||
static const struct iio_chan_spec max1136_channels[] =
|
||||
MAX1363_4X_CHANS(10, NULL, 0);
|
||||
static const struct iio_chan_spec max1236_channels[] =
|
||||
MAX1363_4X_CHANS(12, NULL, 0);
|
||||
static const struct iio_chan_spec max1361_channels[] =
|
||||
MAX1363_4X_CHANS(10, MAX1363_EV_M);
|
||||
MAX1363_4X_CHANS(10, max1363_events, ARRAY_SIZE(max1363_events));
|
||||
static const struct iio_chan_spec max1363_channels[] =
|
||||
MAX1363_4X_CHANS(12, MAX1363_EV_M);
|
||||
MAX1363_4X_CHANS(12, max1363_events, ARRAY_SIZE(max1363_events));
|
||||
|
||||
/* Applies to max1236, max1237 */
|
||||
static const enum max1363_modes max1236_mode_list[] = {
|
||||
|
@ -509,32 +524,32 @@ static const enum max1363_modes max1238_mode_list[] = {
|
|||
d6m7to8m9, d6m7to10m11, d7m6to9m8, d7m6to11m10,
|
||||
};
|
||||
|
||||
#define MAX1363_12X_CHANS(bits) { \
|
||||
MAX1363_CHAN_U(0, _s0, 0, bits, 0), \
|
||||
MAX1363_CHAN_U(1, _s1, 1, bits, 0), \
|
||||
MAX1363_CHAN_U(2, _s2, 2, bits, 0), \
|
||||
MAX1363_CHAN_U(3, _s3, 3, bits, 0), \
|
||||
MAX1363_CHAN_U(4, _s4, 4, bits, 0), \
|
||||
MAX1363_CHAN_U(5, _s5, 5, bits, 0), \
|
||||
MAX1363_CHAN_U(6, _s6, 6, bits, 0), \
|
||||
MAX1363_CHAN_U(7, _s7, 7, bits, 0), \
|
||||
MAX1363_CHAN_U(8, _s8, 8, bits, 0), \
|
||||
MAX1363_CHAN_U(9, _s9, 9, bits, 0), \
|
||||
MAX1363_CHAN_U(10, _s10, 10, bits, 0), \
|
||||
MAX1363_CHAN_U(11, _s11, 11, bits, 0), \
|
||||
MAX1363_CHAN_B(0, 1, d0m1, 12, bits, 0), \
|
||||
MAX1363_CHAN_B(2, 3, d2m3, 13, bits, 0), \
|
||||
MAX1363_CHAN_B(4, 5, d4m5, 14, bits, 0), \
|
||||
MAX1363_CHAN_B(6, 7, d6m7, 15, bits, 0), \
|
||||
MAX1363_CHAN_B(8, 9, d8m9, 16, bits, 0), \
|
||||
MAX1363_CHAN_B(10, 11, d10m11, 17, bits, 0), \
|
||||
MAX1363_CHAN_B(1, 0, d1m0, 18, bits, 0), \
|
||||
MAX1363_CHAN_B(3, 2, d3m2, 19, bits, 0), \
|
||||
MAX1363_CHAN_B(5, 4, d5m4, 20, bits, 0), \
|
||||
MAX1363_CHAN_B(7, 6, d7m6, 21, bits, 0), \
|
||||
MAX1363_CHAN_B(9, 8, d9m8, 22, bits, 0), \
|
||||
MAX1363_CHAN_B(11, 10, d11m10, 23, bits, 0), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(24) \
|
||||
#define MAX1363_12X_CHANS(bits) { \
|
||||
MAX1363_CHAN_U(0, _s0, 0, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(1, _s1, 1, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(2, _s2, 2, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(3, _s3, 3, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(4, _s4, 4, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(5, _s5, 5, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(6, _s6, 6, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(7, _s7, 7, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(8, _s8, 8, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(9, _s9, 9, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(10, _s10, 10, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(11, _s11, 11, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(0, 1, d0m1, 12, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(2, 3, d2m3, 13, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(4, 5, d4m5, 14, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(6, 7, d6m7, 15, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(8, 9, d8m9, 16, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(10, 11, d10m11, 17, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(1, 0, d1m0, 18, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(3, 2, d3m2, 19, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(5, 4, d5m4, 20, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(7, 6, d7m6, 21, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(9, 8, d9m8, 22, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(11, 10, d11m10, 23, bits, NULL, 0), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(24) \
|
||||
}
|
||||
static const struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8);
|
||||
static const struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10);
|
||||
|
@ -559,22 +574,22 @@ static const enum max1363_modes max11608_mode_list[] = {
|
|||
};
|
||||
|
||||
#define MAX1363_8X_CHANS(bits) { \
|
||||
MAX1363_CHAN_U(0, _s0, 0, bits, 0), \
|
||||
MAX1363_CHAN_U(1, _s1, 1, bits, 0), \
|
||||
MAX1363_CHAN_U(2, _s2, 2, bits, 0), \
|
||||
MAX1363_CHAN_U(3, _s3, 3, bits, 0), \
|
||||
MAX1363_CHAN_U(4, _s4, 4, bits, 0), \
|
||||
MAX1363_CHAN_U(5, _s5, 5, bits, 0), \
|
||||
MAX1363_CHAN_U(6, _s6, 6, bits, 0), \
|
||||
MAX1363_CHAN_U(7, _s7, 7, bits, 0), \
|
||||
MAX1363_CHAN_B(0, 1, d0m1, 8, bits, 0), \
|
||||
MAX1363_CHAN_B(2, 3, d2m3, 9, bits, 0), \
|
||||
MAX1363_CHAN_B(4, 5, d4m5, 10, bits, 0), \
|
||||
MAX1363_CHAN_B(6, 7, d6m7, 11, bits, 0), \
|
||||
MAX1363_CHAN_B(1, 0, d1m0, 12, bits, 0), \
|
||||
MAX1363_CHAN_B(3, 2, d3m2, 13, bits, 0), \
|
||||
MAX1363_CHAN_B(5, 4, d5m4, 14, bits, 0), \
|
||||
MAX1363_CHAN_B(7, 6, d7m6, 15, bits, 0), \
|
||||
MAX1363_CHAN_U(0, _s0, 0, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(1, _s1, 1, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(2, _s2, 2, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(3, _s3, 3, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(4, _s4, 4, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(5, _s5, 5, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(6, _s6, 6, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(7, _s7, 7, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(0, 1, d0m1, 8, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(2, 3, d2m3, 9, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(4, 5, d4m5, 10, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(6, 7, d6m7, 11, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(1, 0, d1m0, 12, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(3, 2, d3m2, 13, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(5, 4, d5m4, 14, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(7, 6, d7m6, 15, bits, NULL, 0), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(16) \
|
||||
}
|
||||
static const struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8);
|
||||
|
@ -586,10 +601,10 @@ static const enum max1363_modes max11644_mode_list[] = {
|
|||
};
|
||||
|
||||
#define MAX1363_2X_CHANS(bits) { \
|
||||
MAX1363_CHAN_U(0, _s0, 0, bits, 0), \
|
||||
MAX1363_CHAN_U(1, _s1, 1, bits, 0), \
|
||||
MAX1363_CHAN_B(0, 1, d0m1, 2, bits, 0), \
|
||||
MAX1363_CHAN_B(1, 0, d1m0, 3, bits, 0), \
|
||||
MAX1363_CHAN_U(0, _s0, 0, bits, NULL, 0), \
|
||||
MAX1363_CHAN_U(1, _s1, 1, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(0, 1, d0m1, 2, bits, NULL, 0), \
|
||||
MAX1363_CHAN_B(1, 0, d1m0, 3, bits, NULL, 0), \
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4) \
|
||||
}
|
||||
|
||||
|
@ -684,20 +699,22 @@ static IIO_CONST_ATTR(sampling_frequency_available,
|
|||
"133000 665000 33300 16600 8300 4200 2000 1000");
|
||||
|
||||
static int max1363_read_thresh(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int *val)
|
||||
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 max1363_state *st = iio_priv(indio_dev);
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
|
||||
*val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)];
|
||||
if (dir == IIO_EV_DIR_FALLING)
|
||||
*val = st->thresh_low[chan->channel];
|
||||
else
|
||||
*val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)];
|
||||
return 0;
|
||||
*val = st->thresh_high[chan->channel];
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int max1363_write_thresh(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int val)
|
||||
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 max1363_state *st = iio_priv(indio_dev);
|
||||
/* make it handle signed correctly as well */
|
||||
|
@ -712,13 +729,15 @@ static int max1363_write_thresh(struct iio_dev *indio_dev,
|
|||
break;
|
||||
}
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_FALLING:
|
||||
st->thresh_low[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)] = val;
|
||||
st->thresh_low[chan->channel] = val;
|
||||
break;
|
||||
case IIO_EV_DIR_RISING:
|
||||
st->thresh_high[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)] = val;
|
||||
st->thresh_high[chan->channel] = val;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -763,14 +782,15 @@ static irqreturn_t max1363_event_handler(int irq, void *private)
|
|||
}
|
||||
|
||||
static int max1363_read_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct max1363_state *st = iio_priv(indio_dev);
|
||||
int val;
|
||||
int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
|
||||
int number = chan->channel;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
|
||||
if (dir == IIO_EV_DIR_FALLING)
|
||||
val = (1 << number) & st->mask_low;
|
||||
else
|
||||
val = (1 << number) & st->mask_high;
|
||||
|
@ -915,17 +935,17 @@ static inline int __max1363_check_event_mask(int thismask, int checkmask)
|
|||
}
|
||||
|
||||
static int max1363_write_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int state)
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
int ret = 0;
|
||||
struct max1363_state *st = iio_priv(indio_dev);
|
||||
u16 unifiedmask;
|
||||
int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
|
||||
int number = chan->channel;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
unifiedmask = st->mask_low | st->mask_high;
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) {
|
||||
if (dir == IIO_EV_DIR_FALLING) {
|
||||
|
||||
if (state == 0)
|
||||
st->mask_low &= ~(1 << number);
|
||||
|
@ -993,10 +1013,10 @@ static const struct iio_info max1238_info = {
|
|||
};
|
||||
|
||||
static const struct iio_info max1363_info = {
|
||||
.read_event_value = &max1363_read_thresh,
|
||||
.write_event_value = &max1363_write_thresh,
|
||||
.read_event_config = &max1363_read_event_config,
|
||||
.write_event_config = &max1363_write_event_config,
|
||||
.read_event_value_new = &max1363_read_thresh,
|
||||
.write_event_value_new = &max1363_write_thresh,
|
||||
.read_event_config_new = &max1363_read_event_config,
|
||||
.write_event_config_new = &max1363_write_event_config,
|
||||
.read_raw = &max1363_read_raw,
|
||||
.update_scan_mode = &max1363_update_scan_mode,
|
||||
.driver_module = THIS_MODULE,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
|
|
@ -166,7 +166,7 @@ static int tiadc_buffer_preenable(struct iio_dev *indio_dev)
|
|||
for (i = 0; i < fifo1count; i++)
|
||||
read = tiadc_readl(adc_dev, REG_FIFO1);
|
||||
|
||||
return iio_sw_buffer_preenable(indio_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tiadc_buffer_postenable(struct iio_dev *indio_dev)
|
||||
|
|
|
@ -12,17 +12,27 @@ struct iio_cb_buffer {
|
|||
struct iio_channel *channels;
|
||||
};
|
||||
|
||||
static struct iio_cb_buffer *buffer_to_cb_buffer(struct iio_buffer *buffer)
|
||||
{
|
||||
return container_of(buffer, struct iio_cb_buffer, buffer);
|
||||
}
|
||||
|
||||
static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data)
|
||||
{
|
||||
struct iio_cb_buffer *cb_buff = container_of(buffer,
|
||||
struct iio_cb_buffer,
|
||||
buffer);
|
||||
|
||||
struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer);
|
||||
return cb_buff->cb(data, cb_buff->private);
|
||||
}
|
||||
|
||||
static void iio_buffer_cb_release(struct iio_buffer *buffer)
|
||||
{
|
||||
struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer);
|
||||
kfree(cb_buff->buffer.scan_mask);
|
||||
kfree(cb_buff);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_access_funcs iio_cb_access = {
|
||||
.store_to = &iio_buffer_cb_store_to,
|
||||
.release = &iio_buffer_cb_release,
|
||||
};
|
||||
|
||||
struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
|
||||
|
@ -104,9 +114,8 @@ EXPORT_SYMBOL_GPL(iio_channel_stop_all_cb);
|
|||
|
||||
void iio_channel_release_all_cb(struct iio_cb_buffer *cb_buff)
|
||||
{
|
||||
kfree(cb_buff->buffer.scan_mask);
|
||||
iio_channel_release_all(cb_buff->channels);
|
||||
kfree(cb_buff);
|
||||
iio_buffer_put(&cb_buff->buffer);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_channel_release_all_cb);
|
||||
|
||||
|
|
|
@ -80,6 +80,29 @@ struct ad5421_state {
|
|||
} data[2] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
static const struct iio_event_spec ad5421_current_event[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_event_spec ad5421_temp_event[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad5421_channels[] = {
|
||||
{
|
||||
.type = IIO_CURRENT,
|
||||
|
@ -92,13 +115,14 @@ static const struct iio_chan_spec ad5421_channels[] = {
|
|||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_OFFSET),
|
||||
.scan_type = IIO_ST('u', 16, 16, 0),
|
||||
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING),
|
||||
.event_spec = ad5421_current_event,
|
||||
.num_event_specs = ARRAY_SIZE(ad5421_current_event),
|
||||
},
|
||||
{
|
||||
.type = IIO_TEMP,
|
||||
.channel = -1,
|
||||
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING),
|
||||
.event_spec = ad5421_temp_event,
|
||||
.num_event_specs = ARRAY_SIZE(ad5421_temp_event),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -353,15 +377,15 @@ static int ad5421_write_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int ad5421_write_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code, int state)
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
struct ad5421_state *st = iio_priv(indio_dev);
|
||||
unsigned int mask;
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
switch (chan->type) {
|
||||
case IIO_CURRENT:
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_RISING)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
mask = AD5421_FAULT_OVER_CURRENT;
|
||||
else
|
||||
mask = AD5421_FAULT_UNDER_CURRENT;
|
||||
|
@ -384,15 +408,15 @@ static int ad5421_write_event_config(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int ad5421_read_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct ad5421_state *st = iio_priv(indio_dev);
|
||||
unsigned int mask;
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
switch (chan->type) {
|
||||
case IIO_CURRENT:
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_RISING)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
mask = AD5421_FAULT_OVER_CURRENT;
|
||||
else
|
||||
mask = AD5421_FAULT_UNDER_CURRENT;
|
||||
|
@ -407,12 +431,14 @@ static int ad5421_read_event_config(struct iio_dev *indio_dev,
|
|||
return (bool)(st->fault_mask & mask);
|
||||
}
|
||||
|
||||
static int ad5421_read_event_value(struct iio_dev *indio_dev, u64 event_code,
|
||||
int *val)
|
||||
static int ad5421_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)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
switch (chan->type) {
|
||||
case IIO_CURRENT:
|
||||
ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
|
||||
if (ret < 0)
|
||||
|
@ -426,15 +452,15 @@ static int ad5421_read_event_value(struct iio_dev *indio_dev, u64 event_code,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static const struct iio_info ad5421_info = {
|
||||
.read_raw = ad5421_read_raw,
|
||||
.write_raw = ad5421_write_raw,
|
||||
.read_event_config = ad5421_read_event_config,
|
||||
.write_event_config = ad5421_write_event_config,
|
||||
.read_event_value = ad5421_read_event_value,
|
||||
.read_event_config_new = ad5421_read_event_config,
|
||||
.write_event_config_new = ad5421_write_event_config,
|
||||
.read_event_value_new = ad5421_read_event_value,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
|
|
@ -32,16 +32,7 @@ int st_gyro_trig_set_state(struct iio_trigger *trig, bool state)
|
|||
|
||||
static int st_gyro_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = st_sensors_set_enable(indio_dev, true);
|
||||
if (err < 0)
|
||||
goto st_gyro_set_enable_error;
|
||||
|
||||
err = iio_sw_buffer_preenable(indio_dev);
|
||||
|
||||
st_gyro_set_enable_error:
|
||||
return err;
|
||||
return st_sensors_set_enable(indio_dev, true);
|
||||
}
|
||||
|
||||
static int st_gyro_buffer_postenable(struct iio_dev *indio_dev)
|
||||
|
|
|
@ -33,6 +33,9 @@ int __iio_add_chan_devattr(const char *postfix,
|
|||
enum iio_shared_by shared_by,
|
||||
struct device *dev,
|
||||
struct list_head *attr_list);
|
||||
void iio_free_chan_devattr_list(struct list_head *attr_list);
|
||||
|
||||
ssize_t iio_format_value(char *buf, unsigned int type, int val, int val2);
|
||||
|
||||
/* Event interface flags */
|
||||
#define IIO_BUSY_BIT_POS 1
|
||||
|
@ -50,6 +53,7 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
|
|||
#define iio_buffer_read_first_n_outer_addr (&iio_buffer_read_first_n_outer)
|
||||
|
||||
void iio_disable_all_buffers(struct iio_dev *indio_dev);
|
||||
void iio_buffer_wakeup_poll(struct iio_dev *indio_dev);
|
||||
|
||||
#else
|
||||
|
||||
|
@ -57,11 +61,13 @@ void iio_disable_all_buffers(struct iio_dev *indio_dev);
|
|||
#define iio_buffer_read_first_n_outer_addr NULL
|
||||
|
||||
static inline void iio_disable_all_buffers(struct iio_dev *indio_dev) {}
|
||||
static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {}
|
||||
|
||||
#endif
|
||||
|
||||
int iio_device_register_eventset(struct iio_dev *indio_dev);
|
||||
void iio_device_unregister_eventset(struct iio_dev *indio_dev);
|
||||
void iio_device_wakeup_eventset(struct iio_dev *indio_dev);
|
||||
int iio_event_getfd(struct iio_dev *indio_dev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/cdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include "iio_core.h"
|
||||
|
@ -48,6 +49,9 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
|
|||
struct iio_dev *indio_dev = filp->private_data;
|
||||
struct iio_buffer *rb = indio_dev->buffer;
|
||||
|
||||
if (!indio_dev->info)
|
||||
return -ENODEV;
|
||||
|
||||
if (!rb || !rb->access->read_first_n)
|
||||
return -EINVAL;
|
||||
return rb->access->read_first_n(rb, n, buf);
|
||||
|
@ -62,6 +66,9 @@ unsigned int iio_buffer_poll(struct file *filp,
|
|||
struct iio_dev *indio_dev = filp->private_data;
|
||||
struct iio_buffer *rb = indio_dev->buffer;
|
||||
|
||||
if (!indio_dev->info)
|
||||
return -ENODEV;
|
||||
|
||||
poll_wait(filp, &rb->pollq, wait);
|
||||
if (rb->stufftoread)
|
||||
return POLLIN | POLLRDNORM;
|
||||
|
@ -69,11 +76,27 @@ unsigned int iio_buffer_poll(struct file *filp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* iio_buffer_wakeup_poll - Wakes up the buffer waitqueue
|
||||
* @indio_dev: The IIO device
|
||||
*
|
||||
* Wakes up the event waitqueue used for poll(). Should usually
|
||||
* be called when the device is unregistered.
|
||||
*/
|
||||
void iio_buffer_wakeup_poll(struct iio_dev *indio_dev)
|
||||
{
|
||||
if (!indio_dev->buffer)
|
||||
return;
|
||||
|
||||
wake_up(&indio_dev->buffer->pollq);
|
||||
}
|
||||
|
||||
void iio_buffer_init(struct iio_buffer *buffer)
|
||||
{
|
||||
INIT_LIST_HEAD(&buffer->demux_list);
|
||||
INIT_LIST_HEAD(&buffer->buffer_list);
|
||||
init_waitqueue_head(&buffer->pollq);
|
||||
kref_init(&buffer->ref);
|
||||
}
|
||||
EXPORT_SYMBOL(iio_buffer_init);
|
||||
|
||||
|
@ -251,23 +274,6 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void iio_buffer_remove_and_free_scan_dev_attr(struct iio_dev *indio_dev,
|
||||
struct iio_dev_attr *p)
|
||||
{
|
||||
kfree(p->dev_attr.attr.name);
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
static void __iio_buffer_attr_cleanup(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_dev_attr *p, *n;
|
||||
struct iio_buffer *buffer = indio_dev->buffer;
|
||||
|
||||
list_for_each_entry_safe(p, n,
|
||||
&buffer->scan_el_dev_attr_list, l)
|
||||
iio_buffer_remove_and_free_scan_dev_attr(indio_dev, p);
|
||||
}
|
||||
|
||||
static const char * const iio_scan_elements_group_name = "scan_elements";
|
||||
|
||||
int iio_buffer_register(struct iio_dev *indio_dev,
|
||||
|
@ -344,7 +350,7 @@ int iio_buffer_register(struct iio_dev *indio_dev,
|
|||
error_free_scan_mask:
|
||||
kfree(buffer->scan_mask);
|
||||
error_cleanup_dynamic:
|
||||
__iio_buffer_attr_cleanup(indio_dev);
|
||||
iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -354,7 +360,7 @@ void iio_buffer_unregister(struct iio_dev *indio_dev)
|
|||
{
|
||||
kfree(indio_dev->buffer->scan_mask);
|
||||
kfree(indio_dev->buffer->scan_el_group.attrs);
|
||||
__iio_buffer_attr_cleanup(indio_dev);
|
||||
iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list);
|
||||
}
|
||||
EXPORT_SYMBOL(iio_buffer_unregister);
|
||||
|
||||
|
@ -454,6 +460,19 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
|
|||
return bytes;
|
||||
}
|
||||
|
||||
static void iio_buffer_activate(struct iio_dev *indio_dev,
|
||||
struct iio_buffer *buffer)
|
||||
{
|
||||
iio_buffer_get(buffer);
|
||||
list_add(&buffer->buffer_list, &indio_dev->buffer_list);
|
||||
}
|
||||
|
||||
static void iio_buffer_deactivate(struct iio_buffer *buffer)
|
||||
{
|
||||
list_del_init(&buffer->buffer_list);
|
||||
iio_buffer_put(buffer);
|
||||
}
|
||||
|
||||
void iio_disable_all_buffers(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_buffer *buffer, *_buffer;
|
||||
|
@ -466,14 +485,28 @@ void iio_disable_all_buffers(struct iio_dev *indio_dev)
|
|||
|
||||
list_for_each_entry_safe(buffer, _buffer,
|
||||
&indio_dev->buffer_list, buffer_list)
|
||||
list_del_init(&buffer->buffer_list);
|
||||
iio_buffer_deactivate(buffer);
|
||||
|
||||
indio_dev->currentmode = INDIO_DIRECT_MODE;
|
||||
if (indio_dev->setup_ops->postdisable)
|
||||
indio_dev->setup_ops->postdisable(indio_dev);
|
||||
}
|
||||
|
||||
int iio_update_buffers(struct iio_dev *indio_dev,
|
||||
static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
|
||||
struct iio_buffer *buffer)
|
||||
{
|
||||
unsigned int bytes;
|
||||
|
||||
if (!buffer->access->set_bytes_per_datum)
|
||||
return;
|
||||
|
||||
bytes = iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
|
||||
buffer->scan_timestamp);
|
||||
|
||||
buffer->access->set_bytes_per_datum(buffer, bytes);
|
||||
}
|
||||
|
||||
static int __iio_update_buffers(struct iio_dev *indio_dev,
|
||||
struct iio_buffer *insert_buffer,
|
||||
struct iio_buffer *remove_buffer)
|
||||
{
|
||||
|
@ -503,9 +536,9 @@ int iio_update_buffers(struct iio_dev *indio_dev,
|
|||
indio_dev->active_scan_mask = NULL;
|
||||
|
||||
if (remove_buffer)
|
||||
list_del_init(&remove_buffer->buffer_list);
|
||||
iio_buffer_deactivate(remove_buffer);
|
||||
if (insert_buffer)
|
||||
list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list);
|
||||
iio_buffer_activate(indio_dev, insert_buffer);
|
||||
|
||||
/* If no buffers in list, we are done */
|
||||
if (list_empty(&indio_dev->buffer_list)) {
|
||||
|
@ -540,7 +573,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
|
|||
* Roll back.
|
||||
* Note can only occur when adding a buffer.
|
||||
*/
|
||||
list_del_init(&insert_buffer->buffer_list);
|
||||
iio_buffer_deactivate(insert_buffer);
|
||||
if (old_mask) {
|
||||
indio_dev->active_scan_mask = old_mask;
|
||||
success = -EINVAL;
|
||||
|
@ -570,7 +603,8 @@ int iio_update_buffers(struct iio_dev *indio_dev,
|
|||
iio_compute_scan_bytes(indio_dev,
|
||||
indio_dev->active_scan_mask,
|
||||
indio_dev->scan_timestamp);
|
||||
list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
|
||||
list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
|
||||
iio_buffer_update_bytes_per_datum(indio_dev, buffer);
|
||||
if (buffer->access->request_update) {
|
||||
ret = buffer->access->request_update(buffer);
|
||||
if (ret) {
|
||||
|
@ -579,6 +613,7 @@ int iio_update_buffers(struct iio_dev *indio_dev,
|
|||
goto error_run_postdisable;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (indio_dev->info->update_scan_mode) {
|
||||
ret = indio_dev->info
|
||||
->update_scan_mode(indio_dev,
|
||||
|
@ -631,13 +666,50 @@ int iio_update_buffers(struct iio_dev *indio_dev,
|
|||
error_remove_inserted:
|
||||
|
||||
if (insert_buffer)
|
||||
list_del_init(&insert_buffer->buffer_list);
|
||||
iio_buffer_deactivate(insert_buffer);
|
||||
indio_dev->active_scan_mask = old_mask;
|
||||
kfree(compound_mask);
|
||||
error_ret:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iio_update_buffers(struct iio_dev *indio_dev,
|
||||
struct iio_buffer *insert_buffer,
|
||||
struct iio_buffer *remove_buffer)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (insert_buffer == remove_buffer)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&indio_dev->info_exist_lock);
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
|
||||
if (insert_buffer && iio_buffer_is_active(insert_buffer))
|
||||
insert_buffer = NULL;
|
||||
|
||||
if (remove_buffer && !iio_buffer_is_active(remove_buffer))
|
||||
remove_buffer = NULL;
|
||||
|
||||
if (!insert_buffer && !remove_buffer) {
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (indio_dev->info == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = __iio_update_buffers(indio_dev, insert_buffer, remove_buffer);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
mutex_unlock(&indio_dev->info_exist_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_update_buffers);
|
||||
|
||||
ssize_t iio_buffer_store_enable(struct device *dev,
|
||||
|
@ -663,10 +735,10 @@ ssize_t iio_buffer_store_enable(struct device *dev,
|
|||
goto done;
|
||||
|
||||
if (requested_state)
|
||||
ret = iio_update_buffers(indio_dev,
|
||||
ret = __iio_update_buffers(indio_dev,
|
||||
indio_dev->buffer, NULL);
|
||||
else
|
||||
ret = iio_update_buffers(indio_dev,
|
||||
ret = __iio_update_buffers(indio_dev,
|
||||
NULL, indio_dev->buffer);
|
||||
|
||||
if (ret < 0)
|
||||
|
@ -677,24 +749,6 @@ ssize_t iio_buffer_store_enable(struct device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL(iio_buffer_store_enable);
|
||||
|
||||
int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_buffer *buffer;
|
||||
unsigned bytes;
|
||||
dev_dbg(&indio_dev->dev, "%s\n", __func__);
|
||||
|
||||
list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
|
||||
if (buffer->access->set_bytes_per_datum) {
|
||||
bytes = iio_compute_scan_bytes(indio_dev,
|
||||
buffer->scan_mask,
|
||||
buffer->scan_timestamp);
|
||||
|
||||
buffer->access->set_bytes_per_datum(buffer, bytes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_sw_buffer_preenable);
|
||||
|
||||
/**
|
||||
* iio_validate_scan_mask_onehot() - Validates that exactly one channel is selected
|
||||
* @indio_dev: the iio device
|
||||
|
@ -952,3 +1006,45 @@ int iio_update_demux(struct iio_dev *indio_dev)
|
|||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_update_demux);
|
||||
|
||||
/**
|
||||
* iio_buffer_release() - Free a buffer's resources
|
||||
* @ref: Pointer to the kref embedded in the iio_buffer struct
|
||||
*
|
||||
* This function is called when the last reference to the buffer has been
|
||||
* dropped. It will typically free all resources allocated by the buffer. Do not
|
||||
* call this function manually, always use iio_buffer_put() when done using a
|
||||
* buffer.
|
||||
*/
|
||||
static void iio_buffer_release(struct kref *ref)
|
||||
{
|
||||
struct iio_buffer *buffer = container_of(ref, struct iio_buffer, ref);
|
||||
|
||||
buffer->access->release(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* iio_buffer_get() - Grab a reference to the buffer
|
||||
* @buffer: The buffer to grab a reference for, may be NULL
|
||||
*
|
||||
* Returns the pointer to the buffer that was passed into the function.
|
||||
*/
|
||||
struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer)
|
||||
{
|
||||
if (buffer)
|
||||
kref_get(&buffer->ref);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_buffer_get);
|
||||
|
||||
/**
|
||||
* iio_buffer_put() - Release the reference to the buffer
|
||||
* @buffer: The buffer to release the reference for, may be NULL
|
||||
*/
|
||||
void iio_buffer_put(struct iio_buffer *buffer)
|
||||
{
|
||||
if (buffer)
|
||||
kref_put(&buffer->ref, iio_buffer_release);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(iio_buffer_put);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "iio_core_trigger.h"
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
|
||||
/* IDA to assign each registered device a unique id */
|
||||
static DEFINE_IDA(iio_ida);
|
||||
|
@ -362,22 +363,20 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(iio_enum_write);
|
||||
|
||||
static ssize_t iio_read_channel_info(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
/**
|
||||
* iio_format_value() - Formats a IIO value into its string representation
|
||||
* @buf: The buffer to which the formated value gets written
|
||||
* @type: One of the IIO_VAL_... constants. This decides how the val and val2
|
||||
* parameters are formatted.
|
||||
* @val: First part of the value, exact meaning depends on the type parameter.
|
||||
* @val2: Second part of the value, exact meaning depends on the type parameter.
|
||||
*/
|
||||
ssize_t iio_format_value(char *buf, unsigned int type, int val, int val2)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
unsigned long long tmp;
|
||||
int val, val2;
|
||||
bool scale_db = false;
|
||||
int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
|
||||
&val, &val2, this_attr->address);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (ret) {
|
||||
switch (type) {
|
||||
case IIO_VAL_INT:
|
||||
return sprintf(buf, "%d\n", val);
|
||||
case IIO_VAL_INT_PLUS_MICRO_DB:
|
||||
|
@ -409,6 +408,22 @@ static ssize_t iio_read_channel_info(struct device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t iio_read_channel_info(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int val, val2;
|
||||
int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
|
||||
&val, &val2, this_attr->address);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return iio_format_value(buf, ret, val, val2);
|
||||
}
|
||||
|
||||
/**
|
||||
* iio_str_to_fixpoint() - Parse a fixed-point number from a string
|
||||
* @str: The string to parse
|
||||
|
@ -793,11 +808,22 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
|
|||
return attrcount;
|
||||
}
|
||||
|
||||
static void iio_device_remove_and_free_read_attr(struct iio_dev *indio_dev,
|
||||
struct iio_dev_attr *p)
|
||||
/**
|
||||
* iio_free_chan_devattr_list() - Free a list of IIO device attributes
|
||||
* @attr_list: List of IIO device attributes
|
||||
*
|
||||
* This function frees the memory allocated for each of the IIO device
|
||||
* attributes in the list. Note: if you want to reuse the list after calling
|
||||
* this function you have to reinitialize it using INIT_LIST_HEAD().
|
||||
*/
|
||||
void iio_free_chan_devattr_list(struct list_head *attr_list)
|
||||
{
|
||||
kfree(p->dev_attr.attr.name);
|
||||
kfree(p);
|
||||
struct iio_dev_attr *p, *n;
|
||||
|
||||
list_for_each_entry_safe(p, n, attr_list, l) {
|
||||
kfree(p->dev_attr.attr.name);
|
||||
kfree(p);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t iio_show_dev_name(struct device *dev,
|
||||
|
@ -813,7 +839,7 @@ static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
|
|||
static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
||||
{
|
||||
int i, ret = 0, attrcount, attrn, attrcount_orig = 0;
|
||||
struct iio_dev_attr *p, *n;
|
||||
struct iio_dev_attr *p;
|
||||
struct attribute **attr;
|
||||
|
||||
/* First count elements in any existing group */
|
||||
|
@ -866,11 +892,7 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
|||
return 0;
|
||||
|
||||
error_clear_attrs:
|
||||
list_for_each_entry_safe(p, n,
|
||||
&indio_dev->channel_attr_list, l) {
|
||||
list_del(&p->l);
|
||||
iio_device_remove_and_free_read_attr(indio_dev, p);
|
||||
}
|
||||
iio_free_chan_devattr_list(&indio_dev->channel_attr_list);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -878,12 +900,7 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev)
|
|||
static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
|
||||
{
|
||||
|
||||
struct iio_dev_attr *p, *n;
|
||||
|
||||
list_for_each_entry_safe(p, n, &indio_dev->channel_attr_list, l) {
|
||||
list_del(&p->l);
|
||||
iio_device_remove_and_free_read_attr(indio_dev, p);
|
||||
}
|
||||
iio_free_chan_devattr_list(&indio_dev->channel_attr_list);
|
||||
kfree(indio_dev->chan_attr_group.attrs);
|
||||
}
|
||||
|
||||
|
@ -895,6 +912,8 @@ static void iio_dev_release(struct device *device)
|
|||
iio_device_unregister_eventset(indio_dev);
|
||||
iio_device_unregister_sysfs(indio_dev);
|
||||
|
||||
iio_buffer_put(indio_dev->buffer);
|
||||
|
||||
ida_simple_remove(&iio_ida, indio_dev->id);
|
||||
kfree(indio_dev);
|
||||
}
|
||||
|
@ -1037,6 +1056,9 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
int __user *ip = (int __user *)arg;
|
||||
int fd;
|
||||
|
||||
if (!indio_dev->info)
|
||||
return -ENODEV;
|
||||
|
||||
if (cmd == IIO_GET_EVENT_FD_IOCTL) {
|
||||
fd = iio_event_getfd(indio_dev);
|
||||
if (copy_to_user(ip, &fd, sizeof(fd)))
|
||||
|
@ -1133,6 +1155,10 @@ void iio_device_unregister(struct iio_dev *indio_dev)
|
|||
iio_disable_all_buffers(indio_dev);
|
||||
|
||||
indio_dev->info = NULL;
|
||||
|
||||
iio_device_wakeup_eventset(indio_dev);
|
||||
iio_buffer_wakeup_poll(indio_dev);
|
||||
|
||||
mutex_unlock(&indio_dev->info_exist_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(iio_device_unregister);
|
||||
|
|
|
@ -76,6 +76,9 @@ static unsigned int iio_event_poll(struct file *filep,
|
|||
struct iio_event_interface *ev_int = indio_dev->event_interface;
|
||||
unsigned int events = 0;
|
||||
|
||||
if (!indio_dev->info)
|
||||
return -ENODEV;
|
||||
|
||||
poll_wait(filep, &ev_int->wait, wait);
|
||||
|
||||
spin_lock_irq(&ev_int->wait.lock);
|
||||
|
@ -96,6 +99,9 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
|
|||
unsigned int copied;
|
||||
int ret;
|
||||
|
||||
if (!indio_dev->info)
|
||||
return -ENODEV;
|
||||
|
||||
if (count < sizeof(struct iio_event_data))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -107,9 +113,14 @@ static ssize_t iio_event_chrdev_read(struct file *filep,
|
|||
}
|
||||
/* Blocking on device; waiting for something to be there */
|
||||
ret = wait_event_interruptible_locked_irq(ev_int->wait,
|
||||
!kfifo_is_empty(&ev_int->det_events));
|
||||
!kfifo_is_empty(&ev_int->det_events) ||
|
||||
indio_dev->info == NULL);
|
||||
if (ret)
|
||||
goto error_unlock;
|
||||
if (indio_dev->info == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto error_unlock;
|
||||
}
|
||||
/* Single access device so no one else can get the data */
|
||||
}
|
||||
|
||||
|
@ -190,6 +201,27 @@ static const char * const iio_ev_dir_text[] = {
|
|||
[IIO_EV_DIR_FALLING] = "falling"
|
||||
};
|
||||
|
||||
static const char * const iio_ev_info_text[] = {
|
||||
[IIO_EV_INFO_ENABLE] = "en",
|
||||
[IIO_EV_INFO_VALUE] = "value",
|
||||
[IIO_EV_INFO_HYSTERESIS] = "hysteresis",
|
||||
};
|
||||
|
||||
static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr)
|
||||
{
|
||||
return attr->c->event_spec[attr->address & 0xffff].dir;
|
||||
}
|
||||
|
||||
static enum iio_event_type iio_ev_attr_type(struct iio_dev_attr *attr)
|
||||
{
|
||||
return attr->c->event_spec[attr->address & 0xffff].type;
|
||||
}
|
||||
|
||||
static enum iio_event_info iio_ev_attr_info(struct iio_dev_attr *attr)
|
||||
{
|
||||
return (attr->address >> 16) & 0xffff;
|
||||
}
|
||||
|
||||
static ssize_t iio_ev_state_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
|
@ -204,9 +236,14 @@ static ssize_t iio_ev_state_store(struct device *dev,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = indio_dev->info->write_event_config(indio_dev,
|
||||
this_attr->address,
|
||||
val);
|
||||
if (indio_dev->info->write_event_config)
|
||||
ret = indio_dev->info->write_event_config(indio_dev,
|
||||
this_attr->address, val);
|
||||
else
|
||||
ret = indio_dev->info->write_event_config_new(indio_dev,
|
||||
this_attr->c, iio_ev_attr_type(this_attr),
|
||||
iio_ev_attr_dir(this_attr), val);
|
||||
|
||||
return (ret < 0) ? ret : len;
|
||||
}
|
||||
|
||||
|
@ -216,9 +253,15 @@ static ssize_t iio_ev_state_show(struct device *dev,
|
|||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int val = indio_dev->info->read_event_config(indio_dev,
|
||||
this_attr->address);
|
||||
int val;
|
||||
|
||||
if (indio_dev->info->read_event_config)
|
||||
val = indio_dev->info->read_event_config(indio_dev,
|
||||
this_attr->address);
|
||||
else
|
||||
val = indio_dev->info->read_event_config_new(indio_dev,
|
||||
this_attr->c, iio_ev_attr_type(this_attr),
|
||||
iio_ev_attr_dir(this_attr));
|
||||
if (val < 0)
|
||||
return val;
|
||||
else
|
||||
|
@ -231,14 +274,24 @@ static ssize_t iio_ev_value_show(struct device *dev,
|
|||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int val, ret;
|
||||
int val, val2;
|
||||
int ret;
|
||||
|
||||
ret = indio_dev->info->read_event_value(indio_dev,
|
||||
this_attr->address, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
if (indio_dev->info->read_event_value) {
|
||||
ret = indio_dev->info->read_event_value(indio_dev,
|
||||
this_attr->address, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", val);
|
||||
} else {
|
||||
ret = indio_dev->info->read_event_value_new(indio_dev,
|
||||
this_attr->c, iio_ev_attr_type(this_attr),
|
||||
iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr),
|
||||
&val, &val2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return iio_format_value(buf, ret, val, val2);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t iio_ev_value_store(struct device *dev,
|
||||
|
@ -248,25 +301,120 @@ static ssize_t iio_ev_value_store(struct device *dev,
|
|||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int val;
|
||||
int val, val2;
|
||||
int ret;
|
||||
|
||||
if (!indio_dev->info->write_event_value)
|
||||
if (!indio_dev->info->write_event_value &&
|
||||
!indio_dev->info->write_event_value_new)
|
||||
return -EINVAL;
|
||||
|
||||
ret = kstrtoint(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = indio_dev->info->write_event_value(indio_dev, this_attr->address,
|
||||
val);
|
||||
if (indio_dev->info->write_event_value) {
|
||||
ret = kstrtoint(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = indio_dev->info->write_event_value(indio_dev,
|
||||
this_attr->address, val);
|
||||
} else {
|
||||
ret = iio_str_to_fixpoint(buf, 100000, &val, &val2);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = indio_dev->info->write_event_value_new(indio_dev,
|
||||
this_attr->c, iio_ev_attr_type(this_attr),
|
||||
iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr),
|
||||
val, val2);
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
|
||||
static int iio_device_add_event(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, unsigned int spec_index,
|
||||
enum iio_event_type type, enum iio_event_direction dir,
|
||||
enum iio_shared_by shared_by, const unsigned long *mask)
|
||||
{
|
||||
ssize_t (*show)(struct device *, struct device_attribute *, char *);
|
||||
ssize_t (*store)(struct device *, struct device_attribute *,
|
||||
const char *, size_t);
|
||||
unsigned int attrcount = 0;
|
||||
unsigned int i;
|
||||
char *postfix;
|
||||
int ret;
|
||||
|
||||
for_each_set_bit(i, mask, sizeof(*mask)) {
|
||||
postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
|
||||
iio_ev_type_text[type], iio_ev_dir_text[dir],
|
||||
iio_ev_info_text[i]);
|
||||
if (postfix == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (i == IIO_EV_INFO_ENABLE) {
|
||||
show = iio_ev_state_show;
|
||||
store = iio_ev_state_store;
|
||||
} else {
|
||||
show = iio_ev_value_show;
|
||||
store = iio_ev_value_store;
|
||||
}
|
||||
|
||||
ret = __iio_add_chan_devattr(postfix, chan, show, store,
|
||||
(i << 16) | spec_index, shared_by, &indio_dev->dev,
|
||||
&indio_dev->event_interface->dev_attr_list);
|
||||
kfree(postfix);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
attrcount++;
|
||||
}
|
||||
|
||||
return attrcount;
|
||||
}
|
||||
|
||||
static int iio_device_add_event_sysfs_new(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan)
|
||||
{
|
||||
int ret = 0, i, attrcount = 0;
|
||||
enum iio_event_direction dir;
|
||||
enum iio_event_type type;
|
||||
|
||||
for (i = 0; i < chan->num_event_specs; i++) {
|
||||
type = chan->event_spec[i].type;
|
||||
dir = chan->event_spec[i].dir;
|
||||
|
||||
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
|
||||
IIO_SEPARATE, &chan->event_spec[i].mask_separate);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
attrcount += ret;
|
||||
|
||||
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
|
||||
IIO_SHARED_BY_TYPE,
|
||||
&chan->event_spec[i].mask_shared_by_type);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
attrcount += ret;
|
||||
|
||||
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
|
||||
IIO_SHARED_BY_DIR,
|
||||
&chan->event_spec[i].mask_shared_by_dir);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
attrcount += ret;
|
||||
|
||||
ret = iio_device_add_event(indio_dev, chan, i, type, dir,
|
||||
IIO_SHARED_BY_ALL,
|
||||
&chan->event_spec[i].mask_shared_by_all);
|
||||
if (ret < 0)
|
||||
goto error_ret;
|
||||
attrcount += ret;
|
||||
}
|
||||
ret = attrcount;
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iio_device_add_event_sysfs_old(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan)
|
||||
{
|
||||
int ret = 0, i, attrcount = 0;
|
||||
|
@ -339,15 +487,14 @@ static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev)
|
||||
|
||||
static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan)
|
||||
{
|
||||
struct iio_dev_attr *p, *n;
|
||||
list_for_each_entry_safe(p, n,
|
||||
&indio_dev->event_interface->
|
||||
dev_attr_list, l) {
|
||||
kfree(p->dev_attr.attr.name);
|
||||
kfree(p);
|
||||
}
|
||||
if (chan->event_mask)
|
||||
return iio_device_add_event_sysfs_old(indio_dev, chan);
|
||||
else
|
||||
return iio_device_add_event_sysfs_new(indio_dev, chan);
|
||||
}
|
||||
|
||||
static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
|
||||
|
@ -369,9 +516,12 @@ static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
|
|||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < indio_dev->num_channels; j++)
|
||||
for (j = 0; j < indio_dev->num_channels; j++) {
|
||||
if (indio_dev->channels[j].event_mask != 0)
|
||||
return true;
|
||||
if (indio_dev->channels[j].num_event_specs != 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -441,18 +591,32 @@ int iio_device_register_eventset(struct iio_dev *indio_dev)
|
|||
return 0;
|
||||
|
||||
error_free_setup_event_lines:
|
||||
__iio_remove_event_config_attrs(indio_dev);
|
||||
iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
|
||||
kfree(indio_dev->event_interface);
|
||||
error_ret:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* iio_device_wakeup_eventset - Wakes up the event waitqueue
|
||||
* @indio_dev: The IIO device
|
||||
*
|
||||
* Wakes up the event waitqueue used for poll() and blocking read().
|
||||
* Should usually be called when the device is unregistered.
|
||||
*/
|
||||
void iio_device_wakeup_eventset(struct iio_dev *indio_dev)
|
||||
{
|
||||
if (indio_dev->event_interface == NULL)
|
||||
return;
|
||||
wake_up(&indio_dev->event_interface->wait);
|
||||
}
|
||||
|
||||
void iio_device_unregister_eventset(struct iio_dev *indio_dev)
|
||||
{
|
||||
if (indio_dev->event_interface == NULL)
|
||||
return;
|
||||
__iio_remove_event_config_attrs(indio_dev);
|
||||
iio_free_chan_devattr_list(&indio_dev->event_interface->dev_attr_list);
|
||||
kfree(indio_dev->event_interface->group.attrs);
|
||||
kfree(indio_dev->event_interface);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <linux/iio/trigger_consumer.h>
|
||||
|
||||
static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
|
||||
.preenable = &iio_sw_buffer_preenable,
|
||||
.postenable = &iio_triggered_buffer_postenable,
|
||||
.predisable = &iio_triggered_buffer_predisable,
|
||||
};
|
||||
|
@ -47,14 +46,17 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
|
|||
irqreturn_t (*pollfunc_th)(int irq, void *p),
|
||||
const struct iio_buffer_setup_ops *setup_ops)
|
||||
{
|
||||
struct iio_buffer *buffer;
|
||||
int ret;
|
||||
|
||||
indio_dev->buffer = iio_kfifo_allocate(indio_dev);
|
||||
if (!indio_dev->buffer) {
|
||||
buffer = iio_kfifo_allocate(indio_dev);
|
||||
if (!buffer) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
|
||||
iio_device_attach_buffer(indio_dev, buffer);
|
||||
|
||||
indio_dev->pollfunc = iio_alloc_pollfunc(pollfunc_bh,
|
||||
pollfunc_th,
|
||||
IRQF_ONESHOT,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
struct iio_kfifo {
|
||||
struct iio_buffer buffer;
|
||||
struct kfifo kf;
|
||||
struct mutex user_lock;
|
||||
int update_needed;
|
||||
};
|
||||
|
||||
|
@ -32,13 +33,18 @@ static int iio_request_update_kfifo(struct iio_buffer *r)
|
|||
int ret = 0;
|
||||
struct iio_kfifo *buf = iio_to_kfifo(r);
|
||||
|
||||
if (!buf->update_needed)
|
||||
goto error_ret;
|
||||
kfifo_free(&buf->kf);
|
||||
ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
|
||||
mutex_lock(&buf->user_lock);
|
||||
if (buf->update_needed) {
|
||||
kfifo_free(&buf->kf);
|
||||
ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
|
||||
buf->buffer.length);
|
||||
buf->update_needed = false;
|
||||
} else {
|
||||
kfifo_reset_out(&buf->kf);
|
||||
}
|
||||
r->stufftoread = false;
|
||||
error_ret:
|
||||
mutex_unlock(&buf->user_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -114,12 +120,13 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
|
|||
int ret, copied;
|
||||
struct iio_kfifo *kf = iio_to_kfifo(r);
|
||||
|
||||
if (n < r->bytes_per_datum || r->bytes_per_datum == 0)
|
||||
return -EINVAL;
|
||||
if (mutex_lock_interruptible(&kf->user_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
ret = kfifo_to_user(&kf->kf, buf, n, &copied);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!kfifo_initialized(&kf->kf) || n < kfifo_esize(&kf->kf))
|
||||
ret = -EINVAL;
|
||||
else
|
||||
ret = kfifo_to_user(&kf->kf, buf, n, &copied);
|
||||
|
||||
if (kfifo_is_empty(&kf->kf))
|
||||
r->stufftoread = false;
|
||||
|
@ -127,9 +134,22 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
|
|||
if (!kfifo_is_empty(&kf->kf))
|
||||
r->stufftoread = true;
|
||||
|
||||
mutex_unlock(&kf->user_lock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
|
||||
{
|
||||
struct iio_kfifo *kf = iio_to_kfifo(buffer);
|
||||
|
||||
mutex_destroy(&kf->user_lock);
|
||||
kfifo_free(&kf->kf);
|
||||
kfree(kf);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_access_funcs kfifo_access_funcs = {
|
||||
.store_to = &iio_store_to_kfifo,
|
||||
.read_first_n = &iio_read_first_n_kfifo,
|
||||
|
@ -138,6 +158,7 @@ static const struct iio_buffer_access_funcs kfifo_access_funcs = {
|
|||
.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
|
||||
.get_length = &iio_get_length_kfifo,
|
||||
.set_length = &iio_set_length_kfifo,
|
||||
.release = &iio_kfifo_buffer_release,
|
||||
};
|
||||
|
||||
struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
|
||||
|
@ -152,13 +173,14 @@ struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
|
|||
kf->buffer.attrs = &iio_kfifo_attribute_group;
|
||||
kf->buffer.access = &kfifo_access_funcs;
|
||||
kf->buffer.length = 2;
|
||||
mutex_init(&kf->user_lock);
|
||||
return &kf->buffer;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_kfifo_allocate);
|
||||
|
||||
void iio_kfifo_free(struct iio_buffer *r)
|
||||
{
|
||||
kfree(iio_to_kfifo(r));
|
||||
iio_buffer_put(r);
|
||||
}
|
||||
EXPORT_SYMBOL(iio_kfifo_free);
|
||||
|
||||
|
|
|
@ -27,6 +27,17 @@ config APDS9300
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called apds9300.
|
||||
|
||||
config CM36651
|
||||
depends on I2C
|
||||
tristate "CM36651 driver"
|
||||
help
|
||||
Say Y here if you use cm36651.
|
||||
This option enables proximity & RGB sensor using
|
||||
Capella cm36651 device driver.
|
||||
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called cm36651.
|
||||
|
||||
config GP2AP020A00F
|
||||
tristate "Sharp GP2AP020A00F Proximity/ALS sensor"
|
||||
depends on I2C
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_ADJD_S311) += adjd_s311.o
|
||||
obj-$(CONFIG_APDS9300) += apds9300.o
|
||||
obj-$(CONFIG_CM36651) += cm36651.o
|
||||
obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
|
||||
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
|
||||
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
|
||||
|
|
|
@ -273,12 +273,14 @@ static int apds9300_read_raw(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int apds9300_read_thresh(struct iio_dev *indio_dev, u64 event_code,
|
||||
int *val)
|
||||
static int apds9300_read_thresh(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 apds9300_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
*val = data->thresh_hi;
|
||||
break;
|
||||
|
@ -289,17 +291,19 @@ static int apds9300_read_thresh(struct iio_dev *indio_dev, u64 event_code,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int apds9300_write_thresh(struct iio_dev *indio_dev, u64 event_code,
|
||||
int val)
|
||||
static int apds9300_write_thresh(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 apds9300_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_RISING)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
ret = apds9300_set_thresh_hi(data, val);
|
||||
else
|
||||
ret = apds9300_set_thresh_low(data, val);
|
||||
|
@ -309,7 +313,9 @@ static int apds9300_write_thresh(struct iio_dev *indio_dev, u64 event_code,
|
|||
}
|
||||
|
||||
static int apds9300_read_interrupt_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct apds9300_data *data = iio_priv(indio_dev);
|
||||
|
||||
|
@ -317,7 +323,8 @@ static int apds9300_read_interrupt_config(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int apds9300_write_interrupt_config(struct iio_dev *indio_dev,
|
||||
u64 event_code, int state)
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
struct apds9300_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
@ -337,10 +344,24 @@ static const struct iio_info apds9300_info_no_irq = {
|
|||
static const struct iio_info apds9300_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = apds9300_read_raw,
|
||||
.read_event_value = apds9300_read_thresh,
|
||||
.write_event_value = apds9300_write_thresh,
|
||||
.read_event_config = apds9300_read_interrupt_config,
|
||||
.write_event_config = apds9300_write_interrupt_config,
|
||||
.read_event_value_new = apds9300_read_thresh,
|
||||
.write_event_value_new = apds9300_write_thresh,
|
||||
.read_event_config_new = apds9300_read_interrupt_config,
|
||||
.write_event_config_new = apds9300_write_interrupt_config,
|
||||
};
|
||||
|
||||
static const struct iio_event_spec apds9300_event_spec[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec apds9300_channels[] = {
|
||||
|
@ -355,10 +376,8 @@ static const struct iio_chan_spec apds9300_channels[] = {
|
|||
.channel2 = IIO_MOD_LIGHT_BOTH,
|
||||
.indexed = true,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING)),
|
||||
.event_spec = apds9300_event_spec,
|
||||
.num_event_specs = ARRAY_SIZE(apds9300_event_spec),
|
||||
}, {
|
||||
.type = IIO_INTENSITY,
|
||||
.channel = 1,
|
||||
|
|
708
drivers/iio/light/cm36651.c
Normal file
708
drivers/iio/light/cm36651.c
Normal file
|
@ -0,0 +1,708 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
|
||||
* Author: Beomho Seo <beomho.seo@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2, as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
|
||||
/* Slave address 0x19 for PS of 7 bit addressing protocol for I2C */
|
||||
#define CM36651_I2C_ADDR_PS 0x19
|
||||
/* Alert Response Address */
|
||||
#define CM36651_ARA 0x0C
|
||||
|
||||
/* Ambient light sensor */
|
||||
#define CM36651_CS_CONF1 0x00
|
||||
#define CM36651_CS_CONF2 0x01
|
||||
#define CM36651_ALS_WH_M 0x02
|
||||
#define CM36651_ALS_WH_L 0x03
|
||||
#define CM36651_ALS_WL_M 0x04
|
||||
#define CM36651_ALS_WL_L 0x05
|
||||
#define CM36651_CS_CONF3 0x06
|
||||
#define CM36651_CS_CONF_REG_NUM 0x02
|
||||
|
||||
/* Proximity sensor */
|
||||
#define CM36651_PS_CONF1 0x00
|
||||
#define CM36651_PS_THD 0x01
|
||||
#define CM36651_PS_CANC 0x02
|
||||
#define CM36651_PS_CONF2 0x03
|
||||
#define CM36651_PS_REG_NUM 0x04
|
||||
|
||||
/* CS_CONF1 command code */
|
||||
#define CM36651_ALS_ENABLE 0x00
|
||||
#define CM36651_ALS_DISABLE 0x01
|
||||
#define CM36651_ALS_INT_EN 0x02
|
||||
#define CM36651_ALS_THRES 0x04
|
||||
|
||||
/* CS_CONF2 command code */
|
||||
#define CM36651_CS_CONF2_DEFAULT_BIT 0x08
|
||||
|
||||
/* CS_CONF3 channel integration time */
|
||||
#define CM36651_CS_IT1 0x00 /* Integration time 80000 usec */
|
||||
#define CM36651_CS_IT2 0x40 /* Integration time 160000 usec */
|
||||
#define CM36651_CS_IT3 0x80 /* Integration time 320000 usec */
|
||||
#define CM36651_CS_IT4 0xC0 /* Integration time 640000 usec */
|
||||
|
||||
/* PS_CONF1 command code */
|
||||
#define CM36651_PS_ENABLE 0x00
|
||||
#define CM36651_PS_DISABLE 0x01
|
||||
#define CM36651_PS_INT_EN 0x02
|
||||
#define CM36651_PS_PERS2 0x04
|
||||
#define CM36651_PS_PERS3 0x08
|
||||
#define CM36651_PS_PERS4 0x0C
|
||||
|
||||
/* PS_CONF1 command code: integration time */
|
||||
#define CM36651_PS_IT1 0x00 /* Integration time 320 usec */
|
||||
#define CM36651_PS_IT2 0x10 /* Integration time 420 usec */
|
||||
#define CM36651_PS_IT3 0x20 /* Integration time 520 usec */
|
||||
#define CM36651_PS_IT4 0x30 /* Integration time 640 usec */
|
||||
|
||||
/* PS_CONF1 command code: duty ratio */
|
||||
#define CM36651_PS_DR1 0x00 /* Duty ratio 1/80 */
|
||||
#define CM36651_PS_DR2 0x40 /* Duty ratio 1/160 */
|
||||
#define CM36651_PS_DR3 0x80 /* Duty ratio 1/320 */
|
||||
#define CM36651_PS_DR4 0xC0 /* Duty ratio 1/640 */
|
||||
|
||||
/* PS_THD command code */
|
||||
#define CM36651_PS_INITIAL_THD 0x05
|
||||
|
||||
/* PS_CANC command code */
|
||||
#define CM36651_PS_CANC_DEFAULT 0x00
|
||||
|
||||
/* PS_CONF2 command code */
|
||||
#define CM36651_PS_HYS1 0x00
|
||||
#define CM36651_PS_HYS2 0x01
|
||||
#define CM36651_PS_SMART_PERS_EN 0x02
|
||||
#define CM36651_PS_DIR_INT 0x04
|
||||
#define CM36651_PS_MS 0x10
|
||||
|
||||
#define CM36651_CS_COLOR_NUM 4
|
||||
|
||||
#define CM36651_CLOSE_PROXIMITY 0x32
|
||||
#define CM36651_FAR_PROXIMITY 0x33
|
||||
|
||||
#define CM36651_CS_INT_TIME_AVAIL "80000 160000 320000 640000"
|
||||
#define CM36651_PS_INT_TIME_AVAIL "320 420 520 640"
|
||||
|
||||
enum cm36651_operation_mode {
|
||||
CM36651_LIGHT_EN,
|
||||
CM36651_PROXIMITY_EN,
|
||||
CM36651_PROXIMITY_EV_EN,
|
||||
};
|
||||
|
||||
enum cm36651_light_channel_idx {
|
||||
CM36651_LIGHT_CHANNEL_IDX_RED,
|
||||
CM36651_LIGHT_CHANNEL_IDX_GREEN,
|
||||
CM36651_LIGHT_CHANNEL_IDX_BLUE,
|
||||
CM36651_LIGHT_CHANNEL_IDX_CLEAR,
|
||||
};
|
||||
|
||||
enum cm36651_command {
|
||||
CM36651_CMD_READ_RAW_LIGHT,
|
||||
CM36651_CMD_READ_RAW_PROXIMITY,
|
||||
CM36651_CMD_PROX_EV_EN,
|
||||
CM36651_CMD_PROX_EV_DIS,
|
||||
};
|
||||
|
||||
static const u8 cm36651_cs_reg[CM36651_CS_CONF_REG_NUM] = {
|
||||
CM36651_CS_CONF1,
|
||||
CM36651_CS_CONF2,
|
||||
};
|
||||
|
||||
static const u8 cm36651_ps_reg[CM36651_PS_REG_NUM] = {
|
||||
CM36651_PS_CONF1,
|
||||
CM36651_PS_THD,
|
||||
CM36651_PS_CANC,
|
||||
CM36651_PS_CONF2,
|
||||
};
|
||||
|
||||
struct cm36651_data {
|
||||
const struct cm36651_platform_data *pdata;
|
||||
struct i2c_client *client;
|
||||
struct i2c_client *ps_client;
|
||||
struct i2c_client *ara_client;
|
||||
struct mutex lock;
|
||||
struct regulator *vled_reg;
|
||||
unsigned long flags;
|
||||
int cs_int_time[CM36651_CS_COLOR_NUM];
|
||||
int ps_int_time;
|
||||
u8 cs_ctrl_regs[CM36651_CS_CONF_REG_NUM];
|
||||
u8 ps_ctrl_regs[CM36651_PS_REG_NUM];
|
||||
u16 color[CM36651_CS_COLOR_NUM];
|
||||
};
|
||||
|
||||
static int cm36651_setup_reg(struct cm36651_data *cm36651)
|
||||
{
|
||||
struct i2c_client *client = cm36651->client;
|
||||
struct i2c_client *ps_client = cm36651->ps_client;
|
||||
int i, ret;
|
||||
|
||||
/* CS initialization */
|
||||
cm36651->cs_ctrl_regs[CM36651_CS_CONF1] = CM36651_ALS_ENABLE |
|
||||
CM36651_ALS_THRES;
|
||||
cm36651->cs_ctrl_regs[CM36651_CS_CONF2] = CM36651_CS_CONF2_DEFAULT_BIT;
|
||||
|
||||
for (i = 0; i < CM36651_CS_CONF_REG_NUM; i++) {
|
||||
ret = i2c_smbus_write_byte_data(client, cm36651_cs_reg[i],
|
||||
cm36651->cs_ctrl_regs[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* PS initialization */
|
||||
cm36651->ps_ctrl_regs[CM36651_PS_CONF1] = CM36651_PS_ENABLE |
|
||||
CM36651_PS_IT2;
|
||||
cm36651->ps_ctrl_regs[CM36651_PS_THD] = CM36651_PS_INITIAL_THD;
|
||||
cm36651->ps_ctrl_regs[CM36651_PS_CANC] = CM36651_PS_CANC_DEFAULT;
|
||||
cm36651->ps_ctrl_regs[CM36651_PS_CONF2] = CM36651_PS_HYS2 |
|
||||
CM36651_PS_DIR_INT | CM36651_PS_SMART_PERS_EN;
|
||||
|
||||
for (i = 0; i < CM36651_PS_REG_NUM; i++) {
|
||||
ret = i2c_smbus_write_byte_data(ps_client, cm36651_ps_reg[i],
|
||||
cm36651->ps_ctrl_regs[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set shutdown mode */
|
||||
ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF1,
|
||||
CM36651_ALS_DISABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(cm36651->ps_client,
|
||||
CM36651_PS_CONF1, CM36651_PS_DISABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cm36651_read_output(struct cm36651_data *cm36651,
|
||||
struct iio_chan_spec const *chan, int *val)
|
||||
{
|
||||
struct i2c_client *client = cm36651->client;
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_LIGHT:
|
||||
*val = i2c_smbus_read_word_data(client, chan->address);
|
||||
if (*val < 0)
|
||||
return ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF1,
|
||||
CM36651_ALS_DISABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_PROXIMITY:
|
||||
*val = i2c_smbus_read_byte(cm36651->ps_client);
|
||||
if (*val < 0)
|
||||
return ret;
|
||||
|
||||
if (!test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags)) {
|
||||
ret = i2c_smbus_write_byte_data(cm36651->ps_client,
|
||||
CM36651_PS_CONF1, CM36651_PS_DISABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t cm36651_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct iio_dev *indio_dev = data;
|
||||
struct cm36651_data *cm36651 = iio_priv(indio_dev);
|
||||
struct i2c_client *client = cm36651->client;
|
||||
int ev_dir, ret;
|
||||
u64 ev_code;
|
||||
|
||||
/*
|
||||
* The PS INT pin is an active low signal that PS INT move logic low
|
||||
* when the object is detect. Once the MCU host received the PS INT
|
||||
* "LOW" signal, the Host needs to read the data at Alert Response
|
||||
* Address(ARA) to clear the PS INT signal. After clearing the PS
|
||||
* INT pin, the PS INT signal toggles from low to high.
|
||||
*/
|
||||
ret = i2c_smbus_read_byte(cm36651->ara_client);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"%s: Data read failed: %d\n", __func__, ret);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
switch (ret) {
|
||||
case CM36651_CLOSE_PROXIMITY:
|
||||
ev_dir = IIO_EV_DIR_RISING;
|
||||
break;
|
||||
case CM36651_FAR_PROXIMITY:
|
||||
ev_dir = IIO_EV_DIR_FALLING;
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev,
|
||||
"%s: Data read wrong: %d\n", __func__, ret);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
ev_code = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
|
||||
CM36651_CMD_READ_RAW_PROXIMITY,
|
||||
IIO_EV_TYPE_THRESH, ev_dir);
|
||||
|
||||
iio_push_event(indio_dev, ev_code, iio_get_time_ns());
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int cm36651_set_operation_mode(struct cm36651_data *cm36651, int cmd)
|
||||
{
|
||||
struct i2c_client *client = cm36651->client;
|
||||
struct i2c_client *ps_client = cm36651->ps_client;
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case CM36651_CMD_READ_RAW_LIGHT:
|
||||
ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF1,
|
||||
cm36651->cs_ctrl_regs[CM36651_CS_CONF1]);
|
||||
break;
|
||||
case CM36651_CMD_READ_RAW_PROXIMITY:
|
||||
if (test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags))
|
||||
return CM36651_PROXIMITY_EV_EN;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(ps_client, CM36651_PS_CONF1,
|
||||
cm36651->ps_ctrl_regs[CM36651_PS_CONF1]);
|
||||
break;
|
||||
case CM36651_CMD_PROX_EV_EN:
|
||||
if (test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags)) {
|
||||
dev_err(&client->dev,
|
||||
"Already proximity event enable state\n");
|
||||
return ret;
|
||||
}
|
||||
set_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags);
|
||||
|
||||
ret = i2c_smbus_write_byte_data(ps_client,
|
||||
cm36651_ps_reg[CM36651_PS_CONF1],
|
||||
CM36651_PS_INT_EN | CM36651_PS_PERS2 | CM36651_PS_IT2);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Proximity enable event failed\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case CM36651_CMD_PROX_EV_DIS:
|
||||
if (!test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags)) {
|
||||
dev_err(&client->dev,
|
||||
"Already proximity event disable state\n");
|
||||
return ret;
|
||||
}
|
||||
clear_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags);
|
||||
ret = i2c_smbus_write_byte_data(ps_client,
|
||||
CM36651_PS_CONF1, CM36651_PS_DISABLE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Write register failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cm36651_read_channel(struct cm36651_data *cm36651,
|
||||
struct iio_chan_spec const *chan, int *val)
|
||||
{
|
||||
struct i2c_client *client = cm36651->client;
|
||||
int cmd, ret;
|
||||
|
||||
if (chan->type == IIO_LIGHT)
|
||||
cmd = CM36651_CMD_READ_RAW_LIGHT;
|
||||
else if (chan->type == IIO_PROXIMITY)
|
||||
cmd = CM36651_CMD_READ_RAW_PROXIMITY;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
ret = cm36651_set_operation_mode(cm36651, cmd);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "CM36651 set operation mode failed\n");
|
||||
return ret;
|
||||
}
|
||||
/* Delay for work after enable operation */
|
||||
msleep(50);
|
||||
ret = cm36651_read_output(cm36651, chan, val);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "CM36651 read output failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cm36651_read_int_time(struct cm36651_data *cm36651,
|
||||
struct iio_chan_spec const *chan, int *val)
|
||||
{
|
||||
switch (chan->type) {
|
||||
case IIO_LIGHT:
|
||||
if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT1)
|
||||
*val = 80000;
|
||||
else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT2)
|
||||
*val = 160000;
|
||||
else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT3)
|
||||
*val = 320000;
|
||||
else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT4)
|
||||
*val = 640000;
|
||||
else
|
||||
return -EINVAL;
|
||||
break;
|
||||
case IIO_PROXIMITY:
|
||||
if (cm36651->ps_int_time == CM36651_PS_IT1)
|
||||
*val = 320;
|
||||
else if (cm36651->ps_int_time == CM36651_PS_IT2)
|
||||
*val = 420;
|
||||
else if (cm36651->ps_int_time == CM36651_PS_IT3)
|
||||
*val = 520;
|
||||
else if (cm36651->ps_int_time == CM36651_PS_IT4)
|
||||
*val = 640;
|
||||
else
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
}
|
||||
|
||||
static int cm36651_write_int_time(struct cm36651_data *cm36651,
|
||||
struct iio_chan_spec const *chan, int val)
|
||||
{
|
||||
struct i2c_client *client = cm36651->client;
|
||||
struct i2c_client *ps_client = cm36651->ps_client;
|
||||
int int_time, ret;
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_LIGHT:
|
||||
if (val == 80000)
|
||||
int_time = CM36651_CS_IT1;
|
||||
else if (val == 160000)
|
||||
int_time = CM36651_CS_IT2;
|
||||
else if (val == 320000)
|
||||
int_time = CM36651_CS_IT3;
|
||||
else if (val == 640000)
|
||||
int_time = CM36651_CS_IT4;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF3,
|
||||
int_time >> 2 * (chan->address));
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "CS integration time write failed\n");
|
||||
return ret;
|
||||
}
|
||||
cm36651->cs_int_time[chan->address] = int_time;
|
||||
break;
|
||||
case IIO_PROXIMITY:
|
||||
if (val == 320)
|
||||
int_time = CM36651_PS_IT1;
|
||||
else if (val == 420)
|
||||
int_time = CM36651_PS_IT2;
|
||||
else if (val == 520)
|
||||
int_time = CM36651_PS_IT3;
|
||||
else if (val == 640)
|
||||
int_time = CM36651_PS_IT4;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(ps_client,
|
||||
CM36651_PS_CONF1, int_time);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "PS integration time write failed\n");
|
||||
return ret;
|
||||
}
|
||||
cm36651->ps_int_time = int_time;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cm36651_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct cm36651_data *cm36651 = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cm36651->lock);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = cm36651_read_channel(cm36651, chan, val);
|
||||
break;
|
||||
case IIO_CHAN_INFO_INT_TIME:
|
||||
ret = cm36651_read_int_time(cm36651, chan, val);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&cm36651->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cm36651_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct cm36651_data *cm36651 = iio_priv(indio_dev);
|
||||
struct i2c_client *client = cm36651->client;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (mask == IIO_CHAN_INFO_INT_TIME) {
|
||||
ret = cm36651_write_int_time(cm36651, chan, val);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Integration time write failed\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cm36651_read_prox_thresh(struct iio_dev *indio_dev,
|
||||
u64 event_code, int *val)
|
||||
{
|
||||
struct cm36651_data *cm36651 = iio_priv(indio_dev);
|
||||
|
||||
*val = cm36651->ps_ctrl_regs[CM36651_PS_THD];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cm36651_write_prox_thresh(struct iio_dev *indio_dev,
|
||||
u64 event_code, int val)
|
||||
{
|
||||
struct cm36651_data *cm36651 = iio_priv(indio_dev);
|
||||
struct i2c_client *client = cm36651->client;
|
||||
int ret;
|
||||
|
||||
if (val < 3 || val > 255)
|
||||
return -EINVAL;
|
||||
|
||||
cm36651->ps_ctrl_regs[CM36651_PS_THD] = val;
|
||||
ret = i2c_smbus_write_byte_data(cm36651->ps_client, CM36651_PS_THD,
|
||||
cm36651->ps_ctrl_regs[CM36651_PS_THD]);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "PS threshold write failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cm36651_write_prox_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code, int state)
|
||||
{
|
||||
struct cm36651_data *cm36651 = iio_priv(indio_dev);
|
||||
int cmd, ret = -EINVAL;
|
||||
|
||||
mutex_lock(&cm36651->lock);
|
||||
|
||||
cmd = state ? CM36651_CMD_PROX_EV_EN : CM36651_CMD_PROX_EV_DIS;
|
||||
ret = cm36651_set_operation_mode(cm36651, cmd);
|
||||
|
||||
mutex_unlock(&cm36651->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cm36651_read_prox_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
{
|
||||
struct cm36651_data *cm36651 = iio_priv(indio_dev);
|
||||
int event_en;
|
||||
|
||||
mutex_lock(&cm36651->lock);
|
||||
|
||||
event_en = test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags);
|
||||
|
||||
mutex_unlock(&cm36651->lock);
|
||||
|
||||
return event_en;
|
||||
}
|
||||
|
||||
#define CM36651_LIGHT_CHANNEL(_color, _idx) { \
|
||||
.type = IIO_LIGHT, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_INT_TIME), \
|
||||
.address = _idx, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_LIGHT_##_color, \
|
||||
} \
|
||||
|
||||
static const struct iio_chan_spec cm36651_channels[] = {
|
||||
{
|
||||
.type = IIO_PROXIMITY,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_INT_TIME),
|
||||
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER)
|
||||
},
|
||||
CM36651_LIGHT_CHANNEL(RED, CM36651_LIGHT_CHANNEL_IDX_RED),
|
||||
CM36651_LIGHT_CHANNEL(GREEN, CM36651_LIGHT_CHANNEL_IDX_GREEN),
|
||||
CM36651_LIGHT_CHANNEL(BLUE, CM36651_LIGHT_CHANNEL_IDX_BLUE),
|
||||
CM36651_LIGHT_CHANNEL(CLEAR, CM36651_LIGHT_CHANNEL_IDX_CLEAR),
|
||||
};
|
||||
|
||||
static IIO_CONST_ATTR(in_illuminance_integration_time_available,
|
||||
CM36651_CS_INT_TIME_AVAIL);
|
||||
static IIO_CONST_ATTR(in_proximity_integration_time_available,
|
||||
CM36651_PS_INT_TIME_AVAIL);
|
||||
|
||||
static struct attribute *cm36651_attributes[] = {
|
||||
&iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr,
|
||||
&iio_const_attr_in_proximity_integration_time_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group cm36651_attribute_group = {
|
||||
.attrs = cm36651_attributes
|
||||
};
|
||||
|
||||
static const struct iio_info cm36651_info = {
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &cm36651_read_raw,
|
||||
.write_raw = &cm36651_write_raw,
|
||||
.read_event_value = &cm36651_read_prox_thresh,
|
||||
.write_event_value = &cm36651_write_prox_thresh,
|
||||
.read_event_config = &cm36651_read_prox_event_config,
|
||||
.write_event_config = &cm36651_write_prox_event_config,
|
||||
.attrs = &cm36651_attribute_group,
|
||||
};
|
||||
|
||||
static int cm36651_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct cm36651_data *cm36651;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm36651));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
cm36651 = iio_priv(indio_dev);
|
||||
|
||||
cm36651->vled_reg = devm_regulator_get(&client->dev, "vled");
|
||||
if (IS_ERR(cm36651->vled_reg)) {
|
||||
dev_err(&client->dev, "get regulator vled failed\n");
|
||||
return PTR_ERR(cm36651->vled_reg);
|
||||
}
|
||||
|
||||
ret = regulator_enable(cm36651->vled_reg);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "enable regulator vled failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
|
||||
cm36651->client = client;
|
||||
cm36651->ps_client = i2c_new_dummy(client->adapter,
|
||||
CM36651_I2C_ADDR_PS);
|
||||
cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA);
|
||||
mutex_init(&cm36651->lock);
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->channels = cm36651_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(cm36651_channels);
|
||||
indio_dev->info = &cm36651_info;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = cm36651_setup_reg(cm36651);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "%s: register setup failed\n", __func__);
|
||||
goto error_disable_reg;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(client->irq, NULL, cm36651_irq_handler,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"cm36651", indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "%s: request irq failed\n", __func__);
|
||||
goto error_disable_reg;
|
||||
}
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "%s: regist device failed\n", __func__);
|
||||
goto error_free_irq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_free_irq:
|
||||
free_irq(client->irq, indio_dev);
|
||||
error_disable_reg:
|
||||
regulator_disable(cm36651->vled_reg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cm36651_remove(struct i2c_client *client)
|
||||
{
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
struct cm36651_data *cm36651 = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
regulator_disable(cm36651->vled_reg);
|
||||
free_irq(client->irq, indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cm36651_id[] = {
|
||||
{ "cm36651", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, cm36651_id);
|
||||
|
||||
static const struct of_device_id cm36651_of_match[] = {
|
||||
{ .compatible = "capella,cm36651" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct i2c_driver cm36651_driver = {
|
||||
.driver = {
|
||||
.name = "cm36651",
|
||||
.of_match_table = of_match_ptr(cm36651_of_match),
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = cm36651_probe,
|
||||
.remove = cm36651_remove,
|
||||
.id_table = cm36651_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(cm36651_driver);
|
||||
|
||||
MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
|
||||
MODULE_DESCRIPTION("CM36651 proximity/ambient light sensor driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -42,6 +42,7 @@
|
|||
#include <linux/irq_work.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -996,11 +997,10 @@ static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static u8 gp2ap020a00f_get_reg_by_event_code(u64 event_code)
|
||||
static u8 gp2ap020a00f_get_thresh_reg(const struct iio_chan_spec *chan,
|
||||
enum iio_event_direction event_dir)
|
||||
{
|
||||
int event_dir = IIO_EVENT_CODE_EXTRACT_DIR(event_code);
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
if (event_dir == IIO_EV_DIR_RISING)
|
||||
return GP2AP020A00F_PH_L_REG;
|
||||
|
@ -1011,13 +1011,19 @@ static u8 gp2ap020a00f_get_reg_by_event_code(u64 event_code)
|
|||
return GP2AP020A00F_TH_L_REG;
|
||||
else
|
||||
return GP2AP020A00F_TL_L_REG;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev,
|
||||
u64 event_code, int val)
|
||||
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 gp2ap020a00f_data *data = iio_priv(indio_dev);
|
||||
bool event_en = false;
|
||||
|
@ -1027,7 +1033,7 @@ static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev,
|
|||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
thresh_reg_l = gp2ap020a00f_get_reg_by_event_code(event_code);
|
||||
thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir);
|
||||
thresh_val_id = GP2AP020A00F_THRESH_VAL_ID(thresh_reg_l);
|
||||
|
||||
if (thresh_val_id > GP2AP020A00F_THRESH_PH) {
|
||||
|
@ -1072,15 +1078,19 @@ static int gp2ap020a00f_write_event_val(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int gp2ap020a00f_read_event_val(struct iio_dev *indio_dev,
|
||||
u64 event_code, int *val)
|
||||
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 gp2ap020a00f_data *data = iio_priv(indio_dev);
|
||||
u8 thresh_reg_l;
|
||||
int err = 0;
|
||||
int err = IIO_VAL_INT;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
thresh_reg_l = gp2ap020a00f_get_reg_by_event_code(event_code);
|
||||
thresh_reg_l = gp2ap020a00f_get_thresh_reg(chan, dir);
|
||||
|
||||
if (thresh_reg_l > GP2AP020A00F_PH_L_REG) {
|
||||
err = -EINVAL;
|
||||
|
@ -1096,7 +1106,7 @@ static int gp2ap020a00f_read_event_val(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int gp2ap020a00f_write_prox_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code, int state)
|
||||
int state)
|
||||
{
|
||||
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
|
||||
enum gp2ap020a00f_cmd cmd_high_ev, cmd_low_ev;
|
||||
|
@ -1151,7 +1161,10 @@ static int gp2ap020a00f_write_prox_event_config(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int gp2ap020a00f_write_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code, int state)
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
int state)
|
||||
{
|
||||
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
|
||||
enum gp2ap020a00f_cmd cmd;
|
||||
|
@ -1159,14 +1172,12 @@ static int gp2ap020a00f_write_event_config(struct iio_dev *indio_dev,
|
|||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
err = gp2ap020a00f_write_prox_event_config(indio_dev,
|
||||
event_code, state);
|
||||
err = gp2ap020a00f_write_prox_event_config(indio_dev, state);
|
||||
break;
|
||||
case IIO_LIGHT:
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code)
|
||||
== IIO_EV_DIR_RISING) {
|
||||
if (dir == IIO_EV_DIR_RISING) {
|
||||
cmd = state ? GP2AP020A00F_CMD_ALS_HIGH_EV_EN :
|
||||
GP2AP020A00F_CMD_ALS_HIGH_EV_DIS;
|
||||
err = gp2ap020a00f_exec_cmd(data, cmd);
|
||||
|
@ -1186,17 +1197,18 @@ static int gp2ap020a00f_write_event_config(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int gp2ap020a00f_read_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct gp2ap020a00f_data *data = iio_priv(indio_dev);
|
||||
int event_en = 0;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
switch (chan->type) {
|
||||
case IIO_PROXIMITY:
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code)
|
||||
== IIO_EV_DIR_RISING)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
event_en = test_bit(GP2AP020A00F_FLAG_PROX_RISING_EV,
|
||||
&data->flags);
|
||||
else
|
||||
|
@ -1204,14 +1216,16 @@ static int gp2ap020a00f_read_event_config(struct iio_dev *indio_dev,
|
|||
&data->flags);
|
||||
break;
|
||||
case IIO_LIGHT:
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code)
|
||||
== IIO_EV_DIR_RISING)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
event_en = test_bit(GP2AP020A00F_FLAG_ALS_RISING_EV,
|
||||
&data->flags);
|
||||
else
|
||||
event_en = test_bit(GP2AP020A00F_FLAG_ALS_FALLING_EV,
|
||||
&data->flags);
|
||||
break;
|
||||
default:
|
||||
event_en = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->lock);
|
||||
|
@ -1292,6 +1306,34 @@ static int gp2ap020a00f_read_raw(struct iio_dev *indio_dev,
|
|||
return err < 0 ? err : IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static const struct iio_event_spec gp2ap020a00f_event_spec_light[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_event_spec gp2ap020a00f_event_spec_prox[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_ROC,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_ROC,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec gp2ap020a00f_channels[] = {
|
||||
{
|
||||
.type = IIO_LIGHT,
|
||||
|
@ -1307,10 +1349,8 @@ static const struct iio_chan_spec gp2ap020a00f_channels[] = {
|
|||
},
|
||||
.scan_index = GP2AP020A00F_SCAN_MODE_LIGHT_CLEAR,
|
||||
.address = GP2AP020A00F_D0_L_REG,
|
||||
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING),
|
||||
.event_spec = gp2ap020a00f_event_spec_light,
|
||||
.num_event_specs = ARRAY_SIZE(gp2ap020a00f_event_spec_light),
|
||||
},
|
||||
{
|
||||
.type = IIO_LIGHT,
|
||||
|
@ -1340,20 +1380,18 @@ static const struct iio_chan_spec gp2ap020a00f_channels[] = {
|
|||
},
|
||||
.scan_index = GP2AP020A00F_SCAN_MODE_PROXIMITY,
|
||||
.address = GP2AP020A00F_D2_L_REG,
|
||||
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_ROC,
|
||||
IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_ROC,
|
||||
IIO_EV_DIR_FALLING),
|
||||
.event_spec = gp2ap020a00f_event_spec_prox,
|
||||
.num_event_specs = ARRAY_SIZE(gp2ap020a00f_event_spec_prox),
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(GP2AP020A00F_CHAN_TIMESTAMP),
|
||||
};
|
||||
|
||||
static const struct iio_info gp2ap020a00f_info = {
|
||||
.read_raw = &gp2ap020a00f_read_raw,
|
||||
.read_event_value = &gp2ap020a00f_read_event_val,
|
||||
.read_event_config = &gp2ap020a00f_read_event_config,
|
||||
.write_event_value = &gp2ap020a00f_write_event_val,
|
||||
.write_event_config = &gp2ap020a00f_write_event_config,
|
||||
.read_event_value_new = &gp2ap020a00f_read_event_val,
|
||||
.read_event_config_new = &gp2ap020a00f_read_event_config,
|
||||
.write_event_value_new = &gp2ap020a00f_write_event_val,
|
||||
.write_event_config_new = &gp2ap020a00f_write_event_config,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -1446,7 +1484,6 @@ static int gp2ap020a00f_buffer_predisable(struct iio_dev *indio_dev)
|
|||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = {
|
||||
.preenable = &iio_sw_buffer_preenable,
|
||||
.postenable = &gp2ap020a00f_buffer_postenable,
|
||||
.predisable = &gp2ap020a00f_buffer_predisable,
|
||||
};
|
||||
|
|
|
@ -526,6 +526,20 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct iio_event_spec tsl2563_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec tsl2563_channels[] = {
|
||||
{
|
||||
.type = IIO_LIGHT,
|
||||
|
@ -538,10 +552,8 @@ static const struct iio_chan_spec tsl2563_channels[] = {
|
|||
.channel2 = IIO_MOD_LIGHT_BOTH,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE),
|
||||
.event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_FALLING)),
|
||||
.event_spec = tsl2563_events,
|
||||
.num_event_specs = ARRAY_SIZE(tsl2563_events),
|
||||
}, {
|
||||
.type = IIO_INTENSITY,
|
||||
.modified = 1,
|
||||
|
@ -552,12 +564,13 @@ static const struct iio_chan_spec tsl2563_channels[] = {
|
|||
};
|
||||
|
||||
static int tsl2563_read_thresh(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int *val)
|
||||
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 tsl2563_chip *chip = iio_priv(indio_dev);
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
*val = chip->high_thres;
|
||||
break;
|
||||
|
@ -568,18 +581,19 @@ static int tsl2563_read_thresh(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int tsl2563_write_thresh(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int val)
|
||||
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 tsl2563_chip *chip = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u8 address;
|
||||
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_RISING)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
address = TSL2563_REG_HIGHLOW;
|
||||
else
|
||||
address = TSL2563_REG_LOWLOW;
|
||||
|
@ -591,7 +605,7 @@ static int tsl2563_write_thresh(struct iio_dev *indio_dev,
|
|||
ret = i2c_smbus_write_byte_data(chip->client,
|
||||
TSL2563_CMD | (address + 1),
|
||||
(val >> 8) & 0xFF);
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_RISING)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
chip->high_thres = val;
|
||||
else
|
||||
chip->low_thres = val;
|
||||
|
@ -620,8 +634,8 @@ static irqreturn_t tsl2563_event_handler(int irq, void *private)
|
|||
}
|
||||
|
||||
static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int state)
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
struct tsl2563_chip *chip = iio_priv(indio_dev);
|
||||
int ret = 0;
|
||||
|
@ -662,7 +676,8 @@ static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct tsl2563_chip *chip = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
@ -687,10 +702,10 @@ static const struct iio_info tsl2563_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &tsl2563_read_raw,
|
||||
.write_raw = &tsl2563_write_raw,
|
||||
.read_event_value = &tsl2563_read_thresh,
|
||||
.write_event_value = &tsl2563_write_thresh,
|
||||
.read_event_config = &tsl2563_read_interrupt_config,
|
||||
.write_event_config = &tsl2563_write_interrupt_config,
|
||||
.read_event_value_new = &tsl2563_read_thresh,
|
||||
.write_event_value_new = &tsl2563_write_thresh,
|
||||
.read_event_config_new = &tsl2563_read_interrupt_config,
|
||||
.write_event_config_new = &tsl2563_write_interrupt_config,
|
||||
};
|
||||
|
||||
static int tsl2563_probe(struct i2c_client *client,
|
||||
|
|
|
@ -25,16 +25,7 @@
|
|||
|
||||
static int st_magn_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = st_sensors_set_enable(indio_dev, true);
|
||||
if (err < 0)
|
||||
goto st_magn_set_enable_error;
|
||||
|
||||
err = iio_sw_buffer_preenable(indio_dev);
|
||||
|
||||
st_magn_set_enable_error:
|
||||
return err;
|
||||
return st_sensors_set_enable(indio_dev, true);
|
||||
}
|
||||
|
||||
static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
|
||||
|
|
|
@ -32,16 +32,7 @@ int st_press_trig_set_state(struct iio_trigger *trig, bool state)
|
|||
|
||||
static int st_press_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = st_sensors_set_enable(indio_dev, true);
|
||||
if (err < 0)
|
||||
goto st_press_set_enable_error;
|
||||
|
||||
err = iio_sw_buffer_preenable(indio_dev);
|
||||
|
||||
st_press_set_enable_error:
|
||||
return err;
|
||||
return st_sensors_set_enable(indio_dev, true);
|
||||
}
|
||||
|
||||
static int st_press_buffer_postenable(struct iio_dev *indio_dev)
|
||||
|
|
|
@ -502,7 +502,7 @@ inline int find_type_by_name(const char *name, const char *type)
|
|||
|
||||
inline int _write_sysfs_int(char *filename, char *basedir, int val, int verify)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
FILE *sysfsfp;
|
||||
int test;
|
||||
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
|
||||
|
|
|
@ -190,15 +190,26 @@ static u8 lis3l02dq_axis_map[3][3] = {
|
|||
};
|
||||
|
||||
static int lis3l02dq_read_thresh(struct iio_dev *indio_dev,
|
||||
u64 e,
|
||||
int *val)
|
||||
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)
|
||||
{
|
||||
return lis3l02dq_read_reg_s16(indio_dev, LIS3L02DQ_REG_THS_L_ADDR, val);
|
||||
int ret;
|
||||
|
||||
ret = lis3l02dq_read_reg_s16(indio_dev, LIS3L02DQ_REG_THS_L_ADDR, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int lis3l02dq_write_thresh(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int val)
|
||||
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)
|
||||
{
|
||||
u16 value = val;
|
||||
return lis3l02dq_spi_write_reg_s16(indio_dev,
|
||||
|
@ -503,9 +514,19 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#define LIS3L02DQ_EVENT_MASK \
|
||||
(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
|
||||
static const struct iio_event_spec lis3l02dq_event[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
|
||||
}
|
||||
};
|
||||
|
||||
#define LIS3L02DQ_CHAN(index, mod) \
|
||||
{ \
|
||||
|
@ -523,7 +544,8 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private)
|
|||
.realbits = 12, \
|
||||
.storagebits = 16, \
|
||||
}, \
|
||||
.event_mask = LIS3L02DQ_EVENT_MASK, \
|
||||
.event_spec = lis3l02dq_event, \
|
||||
.num_event_specs = ARRAY_SIZE(lis3l02dq_event), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec lis3l02dq_channels[] = {
|
||||
|
@ -535,14 +557,14 @@ static const struct iio_chan_spec lis3l02dq_channels[] = {
|
|||
|
||||
|
||||
static int lis3l02dq_read_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
|
||||
u8 val;
|
||||
int ret;
|
||||
u8 mask = (1 << (IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code)*2 +
|
||||
(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_RISING)));
|
||||
u8 mask = (1 << (chan->channel2*2 + (dir == IIO_EV_DIR_RISING)));
|
||||
ret = lis3l02dq_spi_read_reg_8(indio_dev,
|
||||
LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
|
||||
&val);
|
||||
|
@ -587,16 +609,16 @@ int lis3l02dq_disable_all_events(struct iio_dev *indio_dev)
|
|||
}
|
||||
|
||||
static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
int state)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 val, control;
|
||||
u8 currentlyset;
|
||||
bool changed = false;
|
||||
u8 mask = (1 << (IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code)*2 +
|
||||
(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_RISING)));
|
||||
u8 mask = (1 << (chan->channel2*2 + (dir == IIO_EV_DIR_RISING)));
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
/* read current control */
|
||||
|
@ -654,10 +676,10 @@ static const struct attribute_group lis3l02dq_attribute_group = {
|
|||
static const struct iio_info lis3l02dq_info = {
|
||||
.read_raw = &lis3l02dq_read_raw,
|
||||
.write_raw = &lis3l02dq_write_raw,
|
||||
.read_event_value = &lis3l02dq_read_thresh,
|
||||
.write_event_value = &lis3l02dq_write_thresh,
|
||||
.write_event_config = &lis3l02dq_write_event_config,
|
||||
.read_event_config = &lis3l02dq_read_event_config,
|
||||
.read_event_value_new = &lis3l02dq_read_thresh,
|
||||
.write_event_value_new = &lis3l02dq_write_thresh,
|
||||
.write_event_config_new = &lis3l02dq_write_event_config,
|
||||
.read_event_config_new = &lis3l02dq_read_event_config,
|
||||
.driver_module = THIS_MODULE,
|
||||
.attrs = &lis3l02dq_attribute_group,
|
||||
};
|
||||
|
|
|
@ -382,7 +382,6 @@ static int lis3l02dq_buffer_predisable(struct iio_dev *indio_dev)
|
|||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops lis3l02dq_buffer_setup_ops = {
|
||||
.preenable = &iio_sw_buffer_preenable,
|
||||
.postenable = &lis3l02dq_buffer_postenable,
|
||||
.predisable = &lis3l02dq_buffer_predisable,
|
||||
};
|
||||
|
@ -396,7 +395,7 @@ int lis3l02dq_configure_buffer(struct iio_dev *indio_dev)
|
|||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
indio_dev->buffer = buffer;
|
||||
iio_device_attach_buffer(indio_dev, buffer);
|
||||
|
||||
buffer->scan_timestamp = true;
|
||||
indio_dev->setup_ops = &lis3l02dq_buffer_setup_ops;
|
||||
|
|
|
@ -419,8 +419,11 @@ static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR,
|
|||
|
||||
static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0);
|
||||
|
||||
#define SCA3000_EVENT_MASK \
|
||||
(IIO_EV_BIT(IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING))
|
||||
static const struct iio_event_spec sca3000_event = {
|
||||
.type = IIO_EV_TYPE_MAG,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
|
||||
};
|
||||
|
||||
#define SCA3000_CHAN(index, mod) \
|
||||
{ \
|
||||
|
@ -437,7 +440,8 @@ static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0);
|
|||
.storagebits = 16, \
|
||||
.shift = 5, \
|
||||
}, \
|
||||
.event_mask = SCA3000_EVENT_MASK, \
|
||||
.event_spec = &sca3000_event, \
|
||||
.num_event_specs = 1, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec sca3000_channels[] = {
|
||||
|
@ -703,12 +707,15 @@ static IIO_CONST_ATTR_TEMP_OFFSET("-214.6");
|
|||
* sca3000_read_thresh() - query of a threshold
|
||||
**/
|
||||
static int sca3000_read_thresh(struct iio_dev *indio_dev,
|
||||
u64 e,
|
||||
int *val)
|
||||
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)
|
||||
{
|
||||
int ret, i;
|
||||
struct sca3000_state *st = iio_priv(indio_dev);
|
||||
int num = IIO_EVENT_CODE_EXTRACT_MODIFIER(e);
|
||||
int num = chan->channel2;
|
||||
mutex_lock(&st->lock);
|
||||
ret = sca3000_read_ctrl_reg(st, sca3000_addresses[num][1]);
|
||||
mutex_unlock(&st->lock);
|
||||
|
@ -724,18 +731,21 @@ static int sca3000_read_thresh(struct iio_dev *indio_dev,
|
|||
ARRAY_SIZE(st->info->mot_det_mult_xz))
|
||||
*val += st->info->mot_det_mult_xz[i];
|
||||
|
||||
return 0;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* sca3000_write_thresh() control of threshold
|
||||
**/
|
||||
static int sca3000_write_thresh(struct iio_dev *indio_dev,
|
||||
u64 e,
|
||||
int val)
|
||||
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 sca3000_state *st = iio_priv(indio_dev);
|
||||
int num = IIO_EVENT_CODE_EXTRACT_MODIFIER(e);
|
||||
int num = chan->channel2;
|
||||
int ret;
|
||||
int i;
|
||||
u8 nonlinear = 0;
|
||||
|
@ -866,12 +876,14 @@ static irqreturn_t sca3000_event_handler(int irq, void *private)
|
|||
* sca3000_read_event_config() what events are enabled
|
||||
**/
|
||||
static int sca3000_read_event_config(struct iio_dev *indio_dev,
|
||||
u64 e)
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct sca3000_state *st = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u8 protect_mask = 0x03;
|
||||
int num = IIO_EVENT_CODE_EXTRACT_MODIFIER(e);
|
||||
int num = chan->channel2;
|
||||
|
||||
/* read current value of mode register */
|
||||
mutex_lock(&st->lock);
|
||||
|
@ -969,13 +981,15 @@ static ssize_t sca3000_set_free_fall_mode(struct device *dev,
|
|||
* this mode is disabled. Currently normal mode is assumed.
|
||||
**/
|
||||
static int sca3000_write_event_config(struct iio_dev *indio_dev,
|
||||
u64 e,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
int state)
|
||||
{
|
||||
struct sca3000_state *st = iio_priv(indio_dev);
|
||||
int ret, ctrlval;
|
||||
u8 protect_mask = 0x03;
|
||||
int num = IIO_EVENT_CODE_EXTRACT_MODIFIER(e);
|
||||
int num = chan->channel2;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
/* First read the motion detector config to find out if
|
||||
|
@ -1112,20 +1126,20 @@ static const struct iio_info sca3000_info = {
|
|||
.attrs = &sca3000_attribute_group,
|
||||
.read_raw = &sca3000_read_raw,
|
||||
.event_attrs = &sca3000_event_attribute_group,
|
||||
.read_event_value = &sca3000_read_thresh,
|
||||
.write_event_value = &sca3000_write_thresh,
|
||||
.read_event_config = &sca3000_read_event_config,
|
||||
.write_event_config = &sca3000_write_event_config,
|
||||
.read_event_value_new = &sca3000_read_thresh,
|
||||
.write_event_value_new = &sca3000_write_thresh,
|
||||
.read_event_config_new = &sca3000_read_event_config,
|
||||
.write_event_config_new = &sca3000_write_event_config,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_info sca3000_info_with_temp = {
|
||||
.attrs = &sca3000_attribute_group_with_temp,
|
||||
.read_raw = &sca3000_read_raw,
|
||||
.read_event_value = &sca3000_read_thresh,
|
||||
.write_event_value = &sca3000_write_thresh,
|
||||
.read_event_config = &sca3000_read_event_config,
|
||||
.write_event_config = &sca3000_write_event_config,
|
||||
.read_event_value_new = &sca3000_read_thresh,
|
||||
.write_event_value_new = &sca3000_write_thresh,
|
||||
.read_event_config_new = &sca3000_read_event_config,
|
||||
.write_event_config_new = &sca3000_write_event_config,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
|
|
@ -265,7 +265,7 @@ static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev)
|
|||
return buf;
|
||||
}
|
||||
|
||||
static inline void sca3000_rb_free(struct iio_buffer *r)
|
||||
static void sca3000_ring_release(struct iio_buffer *r)
|
||||
{
|
||||
kfree(iio_to_hw_buf(r));
|
||||
}
|
||||
|
@ -274,23 +274,28 @@ static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = {
|
|||
.read_first_n = &sca3000_read_first_n_hw_rb,
|
||||
.get_length = &sca3000_ring_get_length,
|
||||
.get_bytes_per_datum = &sca3000_ring_get_bytes_per_datum,
|
||||
.release = sca3000_ring_release,
|
||||
};
|
||||
|
||||
int sca3000_configure_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
indio_dev->buffer = sca3000_rb_allocate(indio_dev);
|
||||
if (indio_dev->buffer == NULL)
|
||||
struct iio_buffer *buffer;
|
||||
|
||||
buffer = sca3000_rb_allocate(indio_dev);
|
||||
if (buffer == NULL)
|
||||
return -ENOMEM;
|
||||
indio_dev->modes |= INDIO_BUFFER_HARDWARE;
|
||||
|
||||
indio_dev->buffer->access = &sca3000_ring_access_funcs;
|
||||
|
||||
iio_device_attach_buffer(indio_dev, buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sca3000_unconfigure_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
sca3000_rb_free(indio_dev->buffer);
|
||||
iio_buffer_put(indio_dev->buffer);
|
||||
}
|
||||
|
||||
static inline
|
||||
|
|
|
@ -102,7 +102,7 @@ config AD7280
|
|||
|
||||
config LPC32XX_ADC
|
||||
tristate "NXP LPC32XX ADC"
|
||||
depends on ARCH_LPC32XX
|
||||
depends on ARCH_LPC32XX || COMPILE_TEST
|
||||
help
|
||||
Say yes here to build support for the integrated ADC inside the
|
||||
LPC32XX SoC. Note that this feature uses the same hardware as the
|
||||
|
@ -113,7 +113,8 @@ config LPC32XX_ADC
|
|||
|
||||
config MXS_LRADC
|
||||
tristate "Freescale i.MX23/i.MX28 LRADC"
|
||||
depends on ARCH_MXS
|
||||
depends on ARCH_MXS || COMPILE_TEST
|
||||
select STMP_DEVICE
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
|
@ -125,7 +126,7 @@ config MXS_LRADC
|
|||
|
||||
config SPEAR_ADC
|
||||
tristate "ST SPEAr ADC"
|
||||
depends on PLAT_SPEAR
|
||||
depends on PLAT_SPEAR || COMPILE_TEST
|
||||
help
|
||||
Say yes here to build support for the integrated ADC inside the
|
||||
ST SPEAr SoC. Provides direct access via sysfs.
|
||||
|
|
|
@ -164,97 +164,14 @@ static irqreturn_t ad7291_event_handler(int irq, void *private)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static inline ssize_t ad7291_show_hyst(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad7291_chip_info *chip = iio_priv(indio_dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
u16 data;
|
||||
int ret;
|
||||
|
||||
ret = ad7291_i2c_read(chip, this_attr->address, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", data & AD7291_VALUE_MASK);
|
||||
}
|
||||
|
||||
static inline ssize_t ad7291_set_hyst(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad7291_chip_info *chip = iio_priv(indio_dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
u16 data;
|
||||
int ret;
|
||||
|
||||
ret = kstrtou16(buf, 10, &data);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (data > AD7291_VALUE_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
ret = ad7291_i2c_write(chip, this_attr->address, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR(in_temp0_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad7291_show_hyst, ad7291_set_hyst,
|
||||
AD7291_HYST(8));
|
||||
static IIO_DEVICE_ATTR(in_voltage0_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(0));
|
||||
static IIO_DEVICE_ATTR(in_voltage1_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(1));
|
||||
static IIO_DEVICE_ATTR(in_voltage2_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(2));
|
||||
static IIO_DEVICE_ATTR(in_voltage3_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(3));
|
||||
static IIO_DEVICE_ATTR(in_voltage4_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(4));
|
||||
static IIO_DEVICE_ATTR(in_voltage5_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(5));
|
||||
static IIO_DEVICE_ATTR(in_voltage6_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(6));
|
||||
static IIO_DEVICE_ATTR(in_voltage7_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad7291_show_hyst, ad7291_set_hyst, AD7291_HYST(7));
|
||||
|
||||
static struct attribute *ad7291_event_attributes[] = {
|
||||
&iio_dev_attr_in_temp0_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage0_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage1_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage2_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage3_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage4_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage5_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage6_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage7_thresh_both_hyst_raw.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static unsigned int ad7291_threshold_reg(u64 event_code)
|
||||
static unsigned int ad7291_threshold_reg(const struct iio_chan_spec *chan,
|
||||
enum iio_event_direction dir, enum iio_event_info info)
|
||||
{
|
||||
unsigned int offset;
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
offset = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
|
||||
offset = chan->channel;
|
||||
break;
|
||||
case IIO_TEMP:
|
||||
offset = 8;
|
||||
|
@ -263,69 +180,78 @@ static unsigned int ad7291_threshold_reg(u64 event_code)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
|
||||
return AD7291_DATA_LOW(offset);
|
||||
else
|
||||
return AD7291_DATA_HIGH(offset);
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
if (dir == IIO_EV_DIR_FALLING)
|
||||
return AD7291_DATA_HIGH(offset);
|
||||
else
|
||||
return AD7291_DATA_LOW(offset);
|
||||
case IIO_EV_INFO_HYSTERESIS:
|
||||
return AD7291_HYST(offset);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad7291_read_event_value(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int *val)
|
||||
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 ad7291_chip_info *chip = iio_priv(indio_dev);
|
||||
int ret;
|
||||
u16 uval;
|
||||
|
||||
ret = ad7291_i2c_read(chip, ad7291_threshold_reg(event_code), &uval);
|
||||
ret = ad7291_i2c_read(chip, ad7291_threshold_reg(chan, dir, info),
|
||||
&uval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
case IIO_VOLTAGE:
|
||||
if (info == IIO_EV_INFO_HYSTERESIS || chan->type == IIO_VOLTAGE)
|
||||
*val = uval & AD7291_VALUE_MASK;
|
||||
return 0;
|
||||
case IIO_TEMP:
|
||||
|
||||
else
|
||||
*val = sign_extend32(uval, 11);
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int ad7291_write_event_value(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int val)
|
||||
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 ad7291_chip_info *chip = iio_priv(indio_dev);
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
case IIO_VOLTAGE:
|
||||
if (info == IIO_EV_INFO_HYSTERESIS || chan->type == IIO_VOLTAGE) {
|
||||
if (val > AD7291_VALUE_MASK || val < 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case IIO_TEMP:
|
||||
} else {
|
||||
if (val > 2047 || val < -2048)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ad7291_i2c_write(chip, ad7291_threshold_reg(event_code), val);
|
||||
return ad7291_i2c_write(chip, ad7291_threshold_reg(chan, dir, info),
|
||||
val);
|
||||
}
|
||||
|
||||
static int ad7291_read_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct ad7291_chip_info *chip = iio_priv(indio_dev);
|
||||
/* To be enabled the channel must simply be on. If any are enabled
|
||||
we are in continuous sampling mode */
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
if (chip->c_mask &
|
||||
(1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN(event_code))))
|
||||
if (chip->c_mask & (1 << (15 - chan->channel)))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
@ -339,11 +265,14 @@ static int ad7291_read_event_config(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int ad7291_write_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
int state)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ad7291_chip_info *chip = iio_priv(indio_dev);
|
||||
unsigned int mask;
|
||||
u16 regval;
|
||||
|
||||
mutex_lock(&chip->state_lock);
|
||||
|
@ -354,16 +283,14 @@ static int ad7291_write_event_config(struct iio_dev *indio_dev,
|
|||
* Possible to disable temp as well but that makes single read tricky.
|
||||
*/
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) {
|
||||
mask = BIT(15 - chan->channel);
|
||||
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
if ((!state) && (chip->c_mask & (1 << (15 -
|
||||
IIO_EVENT_CODE_EXTRACT_CHAN(event_code)))))
|
||||
chip->c_mask &= ~(1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN
|
||||
(event_code)));
|
||||
else if (state && (!(chip->c_mask & (1 << (15 -
|
||||
IIO_EVENT_CODE_EXTRACT_CHAN(event_code))))))
|
||||
chip->c_mask |= (1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN
|
||||
(event_code)));
|
||||
if ((!state) && (chip->c_mask & mask))
|
||||
chip->c_mask &= ~mask;
|
||||
else if (state && (!(chip->c_mask & mask)))
|
||||
chip->c_mask |= mask;
|
||||
else
|
||||
break;
|
||||
|
||||
|
@ -473,6 +400,24 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
static const struct iio_event_spec ad7291_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_EITHER,
|
||||
.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
|
||||
},
|
||||
};
|
||||
|
||||
#define AD7291_VOLTAGE_CHAN(_chan) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
|
@ -480,8 +425,8 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
|
|||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.indexed = 1, \
|
||||
.channel = _chan, \
|
||||
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)|\
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) \
|
||||
.event_spec = ad7291_events, \
|
||||
.num_event_specs = ARRAY_SIZE(ad7291_events), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec ad7291_channels[] = {
|
||||
|
@ -500,23 +445,17 @@ static const struct iio_chan_spec ad7291_channels[] = {
|
|||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.event_mask =
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)|
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)
|
||||
.event_spec = ad7291_events,
|
||||
.num_event_specs = ARRAY_SIZE(ad7291_events),
|
||||
}
|
||||
};
|
||||
|
||||
static struct attribute_group ad7291_event_attribute_group = {
|
||||
.attrs = ad7291_event_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info ad7291_info = {
|
||||
.read_raw = &ad7291_read_raw,
|
||||
.read_event_config = &ad7291_read_event_config,
|
||||
.write_event_config = &ad7291_write_event_config,
|
||||
.read_event_value = &ad7291_read_event_value,
|
||||
.write_event_value = &ad7291_write_event_value,
|
||||
.event_attrs = &ad7291_event_attribute_group,
|
||||
.read_event_config_new = &ad7291_read_event_config,
|
||||
.write_event_config_new = &ad7291_write_event_config,
|
||||
.read_event_value_new = &ad7291_read_event_value,
|
||||
.write_event_value_new = &ad7291_write_event_value,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
|
|
@ -36,18 +36,10 @@
|
|||
#define AD7998_ALERT_STAT_REG 0x1
|
||||
#define AD7998_CONF_REG 0x2
|
||||
#define AD7998_CYCLE_TMR_REG 0x3
|
||||
#define AD7998_DATALOW_CH1_REG 0x4
|
||||
#define AD7998_DATAHIGH_CH1_REG 0x5
|
||||
#define AD7998_HYST_CH1_REG 0x6
|
||||
#define AD7998_DATALOW_CH2_REG 0x7
|
||||
#define AD7998_DATAHIGH_CH2_REG 0x8
|
||||
#define AD7998_HYST_CH2_REG 0x9
|
||||
#define AD7998_DATALOW_CH3_REG 0xA
|
||||
#define AD7998_DATAHIGH_CH3_REG 0xB
|
||||
#define AD7998_HYST_CH3_REG 0xC
|
||||
#define AD7998_DATALOW_CH4_REG 0xD
|
||||
#define AD7998_DATAHIGH_CH4_REG 0xE
|
||||
#define AD7998_HYST_CH4_REG 0xF
|
||||
|
||||
#define AD7998_DATALOW_REG(x) ((x) * 3 + 0x4)
|
||||
#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5)
|
||||
#define AD7998_HYST_REG(x) ((x) * 3 + 0x6)
|
||||
|
||||
#define AD7998_CYC_MASK 0x7
|
||||
#define AD7998_CYC_DIS 0x0
|
||||
|
|
|
@ -252,98 +252,70 @@ static ssize_t ad799x_write_frequency(struct device *dev,
|
|||
}
|
||||
|
||||
static int ad799x_read_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const u8 ad799x_threshold_addresses[][2] = {
|
||||
{ AD7998_DATALOW_CH1_REG, AD7998_DATAHIGH_CH1_REG },
|
||||
{ AD7998_DATALOW_CH2_REG, AD7998_DATAHIGH_CH2_REG },
|
||||
{ AD7998_DATALOW_CH3_REG, AD7998_DATAHIGH_CH3_REG },
|
||||
{ AD7998_DATALOW_CH4_REG, AD7998_DATAHIGH_CH4_REG },
|
||||
};
|
||||
static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan,
|
||||
enum iio_event_direction dir,
|
||||
enum iio_event_info info)
|
||||
{
|
||||
switch (info) {
|
||||
case IIO_EV_INFO_VALUE:
|
||||
if (dir == IIO_EV_DIR_FALLING)
|
||||
return AD7998_DATALOW_REG(chan->channel);
|
||||
else
|
||||
return AD7998_DATAHIGH_REG(chan->channel);
|
||||
case IIO_EV_INFO_HYSTERESIS:
|
||||
return AD7998_HYST_REG(chan->channel);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad799x_write_event_value(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int val)
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
int direction = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_FALLING);
|
||||
int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = ad799x_i2c_write16(st,
|
||||
ad799x_threshold_addresses[number][direction],
|
||||
val);
|
||||
ret = ad799x_i2c_write16(st, ad799x_threshold_reg(chan, dir, info),
|
||||
val);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ad799x_read_event_value(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int *val)
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
int direction = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_FALLING);
|
||||
int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
|
||||
u16 valin;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = ad799x_i2c_read16(st,
|
||||
ad799x_threshold_addresses[number][direction],
|
||||
&valin);
|
||||
ret = ad799x_i2c_read16(st, ad799x_threshold_reg(chan, dir, info),
|
||||
&valin);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = valin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ad799x_read_channel_config(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
|
||||
int ret;
|
||||
u16 val;
|
||||
ret = ad799x_i2c_read16(st, this_attr->address, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
|
||||
static ssize_t ad799x_write_channel_config(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct ad799x_state *st = iio_priv(indio_dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
|
||||
long val;
|
||||
int ret;
|
||||
|
||||
ret = kstrtol(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
ret = ad799x_i2c_write16(st, this_attr->address, val);
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret ? ret : len;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static irqreturn_t ad799x_event_handler(int irq, void *private)
|
||||
|
@ -381,60 +353,19 @@ static irqreturn_t ad799x_event_handler(int irq, void *private)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR(in_voltage0_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad799x_read_channel_config,
|
||||
ad799x_write_channel_config,
|
||||
AD7998_HYST_CH1_REG);
|
||||
|
||||
static IIO_DEVICE_ATTR(in_voltage1_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad799x_read_channel_config,
|
||||
ad799x_write_channel_config,
|
||||
AD7998_HYST_CH2_REG);
|
||||
|
||||
static IIO_DEVICE_ATTR(in_voltage2_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad799x_read_channel_config,
|
||||
ad799x_write_channel_config,
|
||||
AD7998_HYST_CH3_REG);
|
||||
|
||||
static IIO_DEVICE_ATTR(in_voltage3_thresh_both_hyst_raw,
|
||||
S_IRUGO | S_IWUSR,
|
||||
ad799x_read_channel_config,
|
||||
ad799x_write_channel_config,
|
||||
AD7998_HYST_CH4_REG);
|
||||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
|
||||
ad799x_read_frequency,
|
||||
ad799x_write_frequency);
|
||||
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("15625 7812 3906 1953 976 488 244 0");
|
||||
|
||||
static struct attribute *ad7993_4_7_8_event_attributes[] = {
|
||||
&iio_dev_attr_in_voltage0_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage1_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage2_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage3_thresh_both_hyst_raw.dev_attr.attr,
|
||||
static struct attribute *ad799x_event_attributes[] = {
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group ad7993_4_7_8_event_attrs_group = {
|
||||
.attrs = ad7993_4_7_8_event_attributes,
|
||||
.name = "events",
|
||||
};
|
||||
|
||||
static struct attribute *ad7992_event_attributes[] = {
|
||||
&iio_dev_attr_in_voltage0_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_in_voltage1_thresh_both_hyst_raw.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency.dev_attr.attr,
|
||||
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group ad7992_event_attrs_group = {
|
||||
.attrs = ad7992_event_attributes,
|
||||
static struct attribute_group ad799x_event_attrs_group = {
|
||||
.attrs = ad799x_event_attributes,
|
||||
.name = "events",
|
||||
};
|
||||
|
||||
|
@ -443,29 +374,35 @@ static const struct iio_info ad7991_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_info ad7992_info = {
|
||||
.read_raw = &ad799x_read_raw,
|
||||
.event_attrs = &ad7992_event_attrs_group,
|
||||
.read_event_config = &ad799x_read_event_config,
|
||||
.read_event_value = &ad799x_read_event_value,
|
||||
.write_event_value = &ad799x_write_event_value,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_info ad7993_4_7_8_info = {
|
||||
.read_raw = &ad799x_read_raw,
|
||||
.event_attrs = &ad7993_4_7_8_event_attrs_group,
|
||||
.read_event_config = &ad799x_read_event_config,
|
||||
.read_event_value = &ad799x_read_event_value,
|
||||
.write_event_value = &ad799x_write_event_value,
|
||||
.event_attrs = &ad799x_event_attrs_group,
|
||||
.read_event_config_new = &ad799x_read_event_config,
|
||||
.read_event_value_new = &ad799x_read_event_value,
|
||||
.write_event_value_new = &ad799x_write_event_value,
|
||||
.driver_module = THIS_MODULE,
|
||||
.update_scan_mode = ad7997_8_update_scan_mode,
|
||||
};
|
||||
|
||||
#define AD799X_EV_MASK (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
|
||||
static const struct iio_event_spec ad799x_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE),
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_EITHER,
|
||||
.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
|
||||
},
|
||||
};
|
||||
|
||||
#define AD799X_CHANNEL(_index, _realbits, _evmask) { \
|
||||
#define _AD799X_CHANNEL(_index, _realbits, _ev_spec, _num_ev_spec) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = (_index), \
|
||||
|
@ -473,16 +410,24 @@ static const struct iio_info ad7993_4_7_8_info = {
|
|||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.scan_index = (_index), \
|
||||
.scan_type = IIO_ST('u', _realbits, 16, 12 - (_realbits)), \
|
||||
.event_mask = (_evmask), \
|
||||
.event_spec = _ev_spec, \
|
||||
.num_event_specs = _num_ev_spec, \
|
||||
}
|
||||
|
||||
#define AD799X_CHANNEL(_index, _realbits) \
|
||||
_AD799X_CHANNEL(_index, _realbits, NULL, 0)
|
||||
|
||||
#define AD799X_CHANNEL_WITH_EVENTS(_index, _realbits) \
|
||||
_AD799X_CHANNEL(_index, _realbits, ad799x_events, \
|
||||
ARRAY_SIZE(ad799x_events))
|
||||
|
||||
static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
|
||||
[ad7991] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 12, 0),
|
||||
AD799X_CHANNEL(1, 12, 0),
|
||||
AD799X_CHANNEL(2, 12, 0),
|
||||
AD799X_CHANNEL(3, 12, 0),
|
||||
AD799X_CHANNEL(0, 12),
|
||||
AD799X_CHANNEL(1, 12),
|
||||
AD799X_CHANNEL(2, 12),
|
||||
AD799X_CHANNEL(3, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.num_channels = 5,
|
||||
|
@ -490,10 +435,10 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
|
|||
},
|
||||
[ad7995] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 10, 0),
|
||||
AD799X_CHANNEL(1, 10, 0),
|
||||
AD799X_CHANNEL(2, 10, 0),
|
||||
AD799X_CHANNEL(3, 10, 0),
|
||||
AD799X_CHANNEL(0, 10),
|
||||
AD799X_CHANNEL(1, 10),
|
||||
AD799X_CHANNEL(2, 10),
|
||||
AD799X_CHANNEL(3, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.num_channels = 5,
|
||||
|
@ -501,10 +446,10 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
|
|||
},
|
||||
[ad7999] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 8, 0),
|
||||
AD799X_CHANNEL(1, 8, 0),
|
||||
AD799X_CHANNEL(2, 8, 0),
|
||||
AD799X_CHANNEL(3, 8, 0),
|
||||
AD799X_CHANNEL(0, 8),
|
||||
AD799X_CHANNEL(1, 8),
|
||||
AD799X_CHANNEL(2, 8),
|
||||
AD799X_CHANNEL(3, 8),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.num_channels = 5,
|
||||
|
@ -512,20 +457,20 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
|
|||
},
|
||||
[ad7992] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 12, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(1, 12, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
},
|
||||
.num_channels = 3,
|
||||
.default_config = AD7998_ALERT_EN,
|
||||
.info = &ad7992_info,
|
||||
.info = &ad7993_4_7_8_info,
|
||||
},
|
||||
[ad7993] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 10, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(1, 10, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(2, 10, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(3, 10, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.num_channels = 5,
|
||||
|
@ -534,10 +479,10 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
|
|||
},
|
||||
[ad7994] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 12, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(1, 12, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(2, 12, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(3, 12, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(4),
|
||||
},
|
||||
.num_channels = 5,
|
||||
|
@ -546,14 +491,14 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
|
|||
},
|
||||
[ad7997] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 10, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(1, 10, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(2, 10, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(3, 10, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(4, 10, 0),
|
||||
AD799X_CHANNEL(5, 10, 0),
|
||||
AD799X_CHANNEL(6, 10, 0),
|
||||
AD799X_CHANNEL(7, 10, 0),
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 10),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 10),
|
||||
AD799X_CHANNEL(4, 10),
|
||||
AD799X_CHANNEL(5, 10),
|
||||
AD799X_CHANNEL(6, 10),
|
||||
AD799X_CHANNEL(7, 10),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
},
|
||||
.num_channels = 9,
|
||||
|
@ -562,14 +507,14 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
|
|||
},
|
||||
[ad7998] = {
|
||||
.channel = {
|
||||
AD799X_CHANNEL(0, 12, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(1, 12, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(2, 12, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(3, 12, AD799X_EV_MASK),
|
||||
AD799X_CHANNEL(4, 12, 0),
|
||||
AD799X_CHANNEL(5, 12, 0),
|
||||
AD799X_CHANNEL(6, 12, 0),
|
||||
AD799X_CHANNEL(7, 12, 0),
|
||||
AD799X_CHANNEL_WITH_EVENTS(0, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(1, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(2, 12),
|
||||
AD799X_CHANNEL_WITH_EVENTS(3, 12),
|
||||
AD799X_CHANNEL(4, 12),
|
||||
AD799X_CHANNEL(5, 12),
|
||||
AD799X_CHANNEL(6, 12),
|
||||
AD799X_CHANNEL(7, 12),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(8),
|
||||
},
|
||||
.num_channels = 9,
|
||||
|
|
|
@ -160,7 +160,7 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if ((irq < 0) || (irq >= NR_IRQS)) {
|
||||
if (irq <= 0) {
|
||||
dev_err(&pdev->dev, "failed getting interrupt resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -1041,10 +1041,6 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
|
|||
goto err_mem;
|
||||
}
|
||||
|
||||
ret = iio_sw_buffer_preenable(iio);
|
||||
if (ret < 0)
|
||||
goto err_buf;
|
||||
|
||||
if (lradc->soc == IMX28_LRADC)
|
||||
mxs_lradc_reg_clear(lradc, LRADC_CTRL1_MX28_LRADC_IRQ_EN_MASK,
|
||||
LRADC_CTRL1);
|
||||
|
@ -1069,8 +1065,6 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
|
|||
|
||||
return 0;
|
||||
|
||||
err_buf:
|
||||
kfree(lradc->buffer);
|
||||
err_mem:
|
||||
mutex_unlock(&lradc->lock);
|
||||
return ret;
|
||||
|
|
|
@ -146,7 +146,6 @@ static int spear_read_raw(struct iio_dev *indio_dev,
|
|||
long mask)
|
||||
{
|
||||
struct spear_adc_info *info = iio_priv(indio_dev);
|
||||
u32 scale_mv;
|
||||
u32 status;
|
||||
|
||||
switch (mask) {
|
||||
|
@ -319,7 +318,7 @@ static int spear_adc_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
info->adc_base_spear3xx =
|
||||
(struct adc_regs_spear3xx *)info->adc_base_spear6xx;
|
||||
(struct adc_regs_spear3xx __iomem *)info->adc_base_spear6xx;
|
||||
|
||||
info->clk = clk_get(dev, NULL);
|
||||
if (IS_ERR(info->clk)) {
|
||||
|
@ -334,7 +333,7 @@ static int spear_adc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if ((irq < 0) || (irq >= NR_IRQS)) {
|
||||
if (irq <= 0) {
|
||||
dev_err(dev, "failed getting interrupt resource\n");
|
||||
ret = -EINVAL;
|
||||
goto errout3;
|
||||
|
|
|
@ -123,14 +123,14 @@ static int ad7150_read_raw(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
static int ad7150_read_event_config(struct iio_dev *indio_dev, u64 event_code)
|
||||
static int ad7150_read_event_config(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
int ret;
|
||||
u8 threshtype;
|
||||
bool adaptive;
|
||||
struct ad7150_chip_info *chip = iio_priv(indio_dev);
|
||||
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_RISING);
|
||||
|
||||
ret = i2c_smbus_read_byte_data(chip->client, AD7150_CFG);
|
||||
if (ret < 0)
|
||||
|
@ -139,42 +139,47 @@ static int ad7150_read_event_config(struct iio_dev *indio_dev, u64 event_code)
|
|||
threshtype = (ret >> 5) & 0x03;
|
||||
adaptive = !!(ret & 0x80);
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) {
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG_ADAPTIVE:
|
||||
if (rising)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
return adaptive && (threshtype == 0x1);
|
||||
else
|
||||
return adaptive && (threshtype == 0x0);
|
||||
case IIO_EV_TYPE_THRESH_ADAPTIVE:
|
||||
if (rising)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
return adaptive && (threshtype == 0x3);
|
||||
else
|
||||
return adaptive && (threshtype == 0x2);
|
||||
|
||||
case IIO_EV_TYPE_THRESH:
|
||||
if (rising)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
return !adaptive && (threshtype == 0x1);
|
||||
else
|
||||
return !adaptive && (threshtype == 0x0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* lock should be held */
|
||||
static int ad7150_write_event_params(struct iio_dev *indio_dev, u64 event_code)
|
||||
static int ad7150_write_event_params(struct iio_dev *indio_dev,
|
||||
unsigned int chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
int ret;
|
||||
u16 value;
|
||||
u8 sens, timeout;
|
||||
struct ad7150_chip_info *chip = iio_priv(indio_dev);
|
||||
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
|
||||
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_RISING);
|
||||
int rising = (dir == IIO_EV_DIR_RISING);
|
||||
u64 event_code;
|
||||
|
||||
event_code = IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, chan, type, dir);
|
||||
|
||||
if (event_code != chip->current_event)
|
||||
return 0;
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) {
|
||||
switch (type) {
|
||||
/* Note completely different from the adaptive versions */
|
||||
case IIO_EV_TYPE_THRESH:
|
||||
value = chip->threshold[rising][chan];
|
||||
|
@ -211,18 +216,20 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev, u64 event_code)
|
|||
}
|
||||
|
||||
static int ad7150_write_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code, int state)
|
||||
const struct iio_chan_spec *chan, enum iio_event_type type,
|
||||
enum iio_event_direction dir, int state)
|
||||
{
|
||||
u8 thresh_type, cfg, adaptive;
|
||||
int ret;
|
||||
struct ad7150_chip_info *chip = iio_priv(indio_dev);
|
||||
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_RISING);
|
||||
int rising = (dir == IIO_EV_DIR_RISING);
|
||||
u64 event_code;
|
||||
|
||||
/* Something must always be turned on */
|
||||
if (state == 0)
|
||||
return -EINVAL;
|
||||
|
||||
event_code = IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, type, dir);
|
||||
if (event_code == chip->current_event)
|
||||
return 0;
|
||||
mutex_lock(&chip->state_lock);
|
||||
|
@ -232,7 +239,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,
|
|||
|
||||
cfg = ret & ~((0x03 << 5) | (0x1 << 7));
|
||||
|
||||
switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) {
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG_ADAPTIVE:
|
||||
adaptive = 1;
|
||||
if (rising)
|
||||
|
@ -268,7 +275,7 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,
|
|||
chip->current_event = event_code;
|
||||
|
||||
/* update control attributes */
|
||||
ret = ad7150_write_event_params(indio_dev, event_code);
|
||||
ret = ad7150_write_event_params(indio_dev, chan->channel, type, dir);
|
||||
error_ret:
|
||||
mutex_unlock(&chip->state_lock);
|
||||
|
||||
|
@ -276,53 +283,52 @@ static int ad7150_write_event_config(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int ad7150_read_event_value(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int *val)
|
||||
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)
|
||||
{
|
||||
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
|
||||
struct ad7150_chip_info *chip = iio_priv(indio_dev);
|
||||
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_RISING);
|
||||
int rising = (dir == IIO_EV_DIR_RISING);
|
||||
|
||||
/* Complex register sharing going on here */
|
||||
switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) {
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG_ADAPTIVE:
|
||||
*val = chip->mag_sensitivity[rising][chan];
|
||||
return 0;
|
||||
|
||||
*val = chip->mag_sensitivity[rising][chan->channel];
|
||||
return IIO_VAL_INT;
|
||||
case IIO_EV_TYPE_THRESH_ADAPTIVE:
|
||||
*val = chip->thresh_sensitivity[rising][chan];
|
||||
return 0;
|
||||
|
||||
*val = chip->thresh_sensitivity[rising][chan->channel];
|
||||
return IIO_VAL_INT;
|
||||
case IIO_EV_TYPE_THRESH:
|
||||
*val = chip->threshold[rising][chan];
|
||||
return 0;
|
||||
|
||||
*val = chip->threshold[rising][chan->channel];
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int ad7150_write_event_value(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int val)
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
struct ad7150_chip_info *chip = iio_priv(indio_dev);
|
||||
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
|
||||
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_RISING);
|
||||
int rising = (dir == IIO_EV_DIR_RISING);
|
||||
|
||||
mutex_lock(&chip->state_lock);
|
||||
switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) {
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG_ADAPTIVE:
|
||||
chip->mag_sensitivity[rising][chan] = val;
|
||||
chip->mag_sensitivity[rising][chan->channel] = val;
|
||||
break;
|
||||
case IIO_EV_TYPE_THRESH_ADAPTIVE:
|
||||
chip->thresh_sensitivity[rising][chan] = val;
|
||||
chip->thresh_sensitivity[rising][chan->channel] = val;
|
||||
break;
|
||||
case IIO_EV_TYPE_THRESH:
|
||||
chip->threshold[rising][chan] = val;
|
||||
chip->threshold[rising][chan->channel] = val;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
@ -330,7 +336,7 @@ static int ad7150_write_event_value(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
/* write back if active */
|
||||
ret = ad7150_write_event_params(indio_dev, event_code);
|
||||
ret = ad7150_write_event_params(indio_dev, chan->channel, type, dir);
|
||||
|
||||
error_ret:
|
||||
mutex_unlock(&chip->state_lock);
|
||||
|
@ -374,17 +380,22 @@ static ssize_t ad7150_store_timeout(struct device *dev,
|
|||
struct ad7150_chip_info *chip = iio_priv(indio_dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address);
|
||||
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address) ==
|
||||
IIO_EV_DIR_RISING);
|
||||
enum iio_event_direction dir;
|
||||
enum iio_event_type type;
|
||||
int rising;
|
||||
u8 data;
|
||||
int ret;
|
||||
|
||||
type = IIO_EVENT_CODE_EXTRACT_TYPE(this_attr->address);
|
||||
dir = IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address);
|
||||
rising = (dir == IIO_EV_DIR_RISING);
|
||||
|
||||
ret = kstrtou8(buf, 10, &data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&chip->state_lock);
|
||||
switch (IIO_EVENT_CODE_EXTRACT_TYPE(this_attr->address)) {
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_MAG_ADAPTIVE:
|
||||
chip->mag_timeout[rising][chan] = data;
|
||||
break;
|
||||
|
@ -396,7 +407,7 @@ static ssize_t ad7150_store_timeout(struct device *dev,
|
|||
goto error_ret;
|
||||
}
|
||||
|
||||
ret = ad7150_write_event_params(indio_dev, this_attr->address);
|
||||
ret = ad7150_write_event_params(indio_dev, chan, type, dir);
|
||||
error_ret:
|
||||
mutex_unlock(&chip->state_lock);
|
||||
|
||||
|
@ -424,6 +435,40 @@ static AD7150_TIMEOUT(0, thresh_adaptive, falling, THRESH_ADAPTIVE, FALLING);
|
|||
static AD7150_TIMEOUT(1, thresh_adaptive, rising, THRESH_ADAPTIVE, RISING);
|
||||
static AD7150_TIMEOUT(1, thresh_adaptive, falling, THRESH_ADAPTIVE, FALLING);
|
||||
|
||||
static const struct iio_event_spec ad7150_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH_ADAPTIVE,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH_ADAPTIVE,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_MAG_ADAPTIVE,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_MAG_ADAPTIVE,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec ad7150_channels[] = {
|
||||
{
|
||||
.type = IIO_CAPACITANCE,
|
||||
|
@ -431,26 +476,16 @@ static const struct iio_chan_spec ad7150_channels[] = {
|
|||
.channel = 0,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_AVERAGE_RAW),
|
||||
.event_mask =
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH_ADAPTIVE, IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH_ADAPTIVE, IIO_EV_DIR_FALLING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_DIR_FALLING)
|
||||
.event_spec = ad7150_events,
|
||||
.num_event_specs = ARRAY_SIZE(ad7150_events),
|
||||
}, {
|
||||
.type = IIO_CAPACITANCE,
|
||||
.indexed = 1,
|
||||
.channel = 1,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_AVERAGE_RAW),
|
||||
.event_mask =
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH_ADAPTIVE, IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH_ADAPTIVE, IIO_EV_DIR_FALLING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_DIR_RISING) |
|
||||
IIO_EV_BIT(IIO_EV_TYPE_MAG_ADAPTIVE, IIO_EV_DIR_FALLING)
|
||||
.event_spec = ad7150_events,
|
||||
.num_event_specs = ARRAY_SIZE(ad7150_events),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -541,10 +576,10 @@ static const struct iio_info ad7150_info = {
|
|||
.event_attrs = &ad7150_event_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &ad7150_read_raw,
|
||||
.read_event_config = &ad7150_read_event_config,
|
||||
.write_event_config = &ad7150_write_event_config,
|
||||
.read_event_value = &ad7150_read_event_value,
|
||||
.write_event_value = &ad7150_write_event_value,
|
||||
.read_event_config_new = &ad7150_read_event_config,
|
||||
.write_event_config_new = &ad7150_write_event_config,
|
||||
.read_event_value_new = &ad7150_read_event_value,
|
||||
.write_event_value_new = &ad7150_write_event_value,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -57,6 +57,20 @@ static const struct iio_dummy_accel_calibscale dummy_scales[] = {
|
|||
{ 733, 13, 0x9 }, /* 733.000013 */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
|
||||
|
||||
/*
|
||||
* simple event - triggered when value rises above
|
||||
* a threshold
|
||||
*/
|
||||
static const struct iio_event_spec iio_dummy_event = {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* iio_dummy_channels - Description of available channels
|
||||
*
|
||||
|
@ -104,12 +118,8 @@ static const struct iio_chan_spec iio_dummy_channels[] = {
|
|||
.shift = 0, /* zero shift */
|
||||
},
|
||||
#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
|
||||
/*
|
||||
* simple event - triggered when value rises above
|
||||
* a threshold
|
||||
*/
|
||||
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING),
|
||||
.event_spec = &iio_dummy_event,
|
||||
.num_event_specs = 1,
|
||||
#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
|
||||
},
|
||||
/* Differential ADC channel in_voltage1-voltage2_raw etc*/
|
||||
|
@ -360,10 +370,10 @@ static const struct iio_info iio_dummy_info = {
|
|||
.read_raw = &iio_dummy_read_raw,
|
||||
.write_raw = &iio_dummy_write_raw,
|
||||
#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
|
||||
.read_event_config = &iio_simple_dummy_read_event_config,
|
||||
.write_event_config = &iio_simple_dummy_write_event_config,
|
||||
.read_event_value = &iio_simple_dummy_read_event_value,
|
||||
.write_event_value = &iio_simple_dummy_write_event_value,
|
||||
.read_event_config_new = &iio_simple_dummy_read_event_config,
|
||||
.write_event_config_new = &iio_simple_dummy_write_event_config,
|
||||
.read_event_value_new = &iio_simple_dummy_read_event_value,
|
||||
.write_event_value_new = &iio_simple_dummy_write_event_value,
|
||||
#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
|
||||
};
|
||||
|
||||
|
|
|
@ -45,19 +45,29 @@ struct iio_dummy_state {
|
|||
struct iio_dev;
|
||||
|
||||
int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code);
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir);
|
||||
|
||||
int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
int state);
|
||||
|
||||
int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int *val);
|
||||
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);
|
||||
|
||||
int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int val);
|
||||
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);
|
||||
|
||||
int iio_simple_dummy_events_register(struct iio_dev *indio_dev);
|
||||
int iio_simple_dummy_events_unregister(struct iio_dev *indio_dev);
|
||||
|
|
|
@ -98,14 +98,6 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
|
|||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = {
|
||||
/*
|
||||
* iio_sw_buffer_preenable:
|
||||
* Generic function for equal sized ring elements + 64 bit timestamp
|
||||
* Assumes that any combination of channels can be enabled.
|
||||
* Typically replaced to implement restrictions on what combinations
|
||||
* can be captured (hardware scan modes).
|
||||
*/
|
||||
.preenable = &iio_sw_buffer_preenable,
|
||||
/*
|
||||
* iio_triggered_buffer_postenable:
|
||||
* Generic function that simply attaches the pollfunc to the trigger.
|
||||
|
@ -135,7 +127,7 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
|
|||
goto error_ret;
|
||||
}
|
||||
|
||||
indio_dev->buffer = buffer;
|
||||
iio_device_attach_buffer(indio_dev, buffer);
|
||||
|
||||
/* Enable timestamps by default */
|
||||
buffer->scan_timestamp = true;
|
||||
|
|
|
@ -23,13 +23,17 @@
|
|||
/**
|
||||
* iio_simple_dummy_read_event_config() - is event enabled?
|
||||
* @indio_dev: the device instance data
|
||||
* @event_code: event code of the event being queried
|
||||
* @chan: channel for the event whose state is being queried
|
||||
* @type: type of the event whose state is being queried
|
||||
* @dir: direction of the vent whose state is being queried
|
||||
*
|
||||
* This function would normally query the relevant registers or a cache to
|
||||
* discover if the event generation is enabled on the device.
|
||||
*/
|
||||
int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct iio_dummy_state *st = iio_priv(indio_dev);
|
||||
|
||||
|
@ -39,7 +43,9 @@ int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev,
|
|||
/**
|
||||
* iio_simple_dummy_write_event_config() - set whether event is enabled
|
||||
* @indio_dev: the device instance data
|
||||
* @event_code: event code of event being enabled/disabled
|
||||
* @chan: channel for the event whose state is being set
|
||||
* @type: type of the event whose state is being set
|
||||
* @dir: direction of the vent whose state is being set
|
||||
* @state: whether to enable or disable the device.
|
||||
*
|
||||
* This function would normally set the relevant registers on the devices
|
||||
|
@ -47,7 +53,9 @@ int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev,
|
|||
* value.
|
||||
*/
|
||||
int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
int state)
|
||||
{
|
||||
struct iio_dummy_state *st = iio_priv(indio_dev);
|
||||
|
@ -56,12 +64,11 @@ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
|
|||
* Deliberately over the top code splitting to illustrate
|
||||
* how this is done when multiple events exist.
|
||||
*/
|
||||
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
|
||||
switch (chan->type) {
|
||||
case IIO_VOLTAGE:
|
||||
switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) {
|
||||
switch (type) {
|
||||
case IIO_EV_TYPE_THRESH:
|
||||
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
|
||||
IIO_EV_DIR_RISING)
|
||||
if (dir == IIO_EV_DIR_RISING)
|
||||
st->event_en = state;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
@ -79,7 +86,10 @@ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
|
|||
/**
|
||||
* iio_simple_dummy_read_event_value() - get value associated with event
|
||||
* @indio_dev: device instance specific data
|
||||
* @event_code: event code for the event whose value is being queried
|
||||
* @chan: channel for the event whose value is being read
|
||||
* @type: type of the event whose value is being read
|
||||
* @dir: direction of the vent whose value is being read
|
||||
* @info: info type of the event whose value is being read
|
||||
* @val: value for the event code.
|
||||
*
|
||||
* Many devices provide a large set of events of which only a subset may
|
||||
|
@ -89,25 +99,34 @@ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
|
|||
* the enabled event is changed.
|
||||
*/
|
||||
int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int *val)
|
||||
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 iio_dummy_state *st = iio_priv(indio_dev);
|
||||
|
||||
*val = st->event_val;
|
||||
|
||||
return 0;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
/**
|
||||
* iio_simple_dummy_write_event_value() - set value associate with event
|
||||
* @indio_dev: device instance specific data
|
||||
* @event_code: event code for the event whose value is being set
|
||||
* @chan: channel for the event whose value is being set
|
||||
* @type: type of the event whose value is being set
|
||||
* @dir: direction of the vent whose value is being set
|
||||
* @info: info type of the event whose value is being set
|
||||
* @val: the value to be set.
|
||||
*/
|
||||
int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int val)
|
||||
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 iio_dummy_state *st = iio_priv(indio_dev);
|
||||
|
||||
|
|
|
@ -574,10 +574,6 @@ static int ad5933_ring_preenable(struct iio_dev *indio_dev)
|
|||
if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
|
||||
return -EINVAL;
|
||||
|
||||
ret = iio_sw_buffer_preenable(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ad5933_reset(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -630,10 +626,14 @@ static const struct iio_buffer_setup_ops ad5933_ring_setup_ops = {
|
|||
|
||||
static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev)
|
||||
{
|
||||
indio_dev->buffer = iio_kfifo_allocate(indio_dev);
|
||||
if (!indio_dev->buffer)
|
||||
struct iio_buffer *buffer;
|
||||
|
||||
buffer = iio_kfifo_allocate(indio_dev);
|
||||
if (buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
iio_device_attach_buffer(indio_dev, buffer);
|
||||
|
||||
/* Ring buffer functions - here trigger setup related */
|
||||
indio_dev->setup_ops = &ad5933_ring_setup_ops;
|
||||
|
||||
|
|
|
@ -124,11 +124,6 @@
|
|||
#define TSL2X7X_mA13 0xD0
|
||||
#define TSL2X7X_MAX_TIMER_CNT (0xFF)
|
||||
|
||||
/*Common device IIO EventMask */
|
||||
#define TSL2X7X_EVENT_MASK \
|
||||
(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
|
||||
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)),
|
||||
|
||||
#define TSL2X7X_MIN_ITIME 3
|
||||
|
||||
/* TAOS txx2x7x Device family members */
|
||||
|
@ -1222,12 +1217,14 @@ static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev,
|
|||
}
|
||||
|
||||
static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev,
|
||||
u64 event_code)
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir)
|
||||
{
|
||||
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY)
|
||||
if (chan->type == IIO_INTENSITY)
|
||||
ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10);
|
||||
else
|
||||
ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20);
|
||||
|
@ -1236,12 +1233,14 @@ static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
int val)
|
||||
{
|
||||
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
|
||||
|
||||
if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
|
||||
if (chan->type == IIO_INTENSITY) {
|
||||
if (val)
|
||||
chip->tsl2x7x_settings.interrupts_en |= 0x10;
|
||||
else
|
||||
|
@ -1259,13 +1258,16 @@ static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int tsl2x7x_write_thresh(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int val)
|
||||
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 tsl2X7X_chip *chip = iio_priv(indio_dev);
|
||||
|
||||
if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
|
||||
switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
|
||||
if (chan->type == IIO_INTENSITY) {
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
chip->tsl2x7x_settings.als_thresh_high = val;
|
||||
break;
|
||||
|
@ -1276,7 +1278,7 @@ static int tsl2x7x_write_thresh(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
chip->tsl2x7x_settings.prox_thres_high = val;
|
||||
break;
|
||||
|
@ -1294,13 +1296,16 @@ static int tsl2x7x_write_thresh(struct iio_dev *indio_dev,
|
|||
}
|
||||
|
||||
static int tsl2x7x_read_thresh(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int *val)
|
||||
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 tsl2X7X_chip *chip = iio_priv(indio_dev);
|
||||
|
||||
if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
|
||||
switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
|
||||
if (chan->type == IIO_INTENSITY) {
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
*val = chip->tsl2x7x_settings.als_thresh_high;
|
||||
break;
|
||||
|
@ -1311,7 +1316,7 @@ static int tsl2x7x_read_thresh(struct iio_dev *indio_dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
|
||||
switch (dir) {
|
||||
case IIO_EV_DIR_RISING:
|
||||
*val = chip->tsl2x7x_settings.prox_thres_high;
|
||||
break;
|
||||
|
@ -1323,7 +1328,7 @@ static int tsl2x7x_read_thresh(struct iio_dev *indio_dev,
|
|||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
|
||||
|
@ -1667,10 +1672,10 @@ static const struct iio_info tsl2X7X_device_info[] = {
|
|||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &tsl2x7x_read_raw,
|
||||
.write_raw = &tsl2x7x_write_raw,
|
||||
.read_event_value = &tsl2x7x_read_thresh,
|
||||
.write_event_value = &tsl2x7x_write_thresh,
|
||||
.read_event_config = &tsl2x7x_read_interrupt_config,
|
||||
.write_event_config = &tsl2x7x_write_interrupt_config,
|
||||
.read_event_value_new = &tsl2x7x_read_thresh,
|
||||
.write_event_value_new = &tsl2x7x_write_thresh,
|
||||
.read_event_config_new = &tsl2x7x_read_interrupt_config,
|
||||
.write_event_config_new = &tsl2x7x_write_interrupt_config,
|
||||
},
|
||||
[PRX] = {
|
||||
.attrs = &tsl2X7X_device_attr_group_tbl[PRX],
|
||||
|
@ -1678,10 +1683,10 @@ static const struct iio_info tsl2X7X_device_info[] = {
|
|||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &tsl2x7x_read_raw,
|
||||
.write_raw = &tsl2x7x_write_raw,
|
||||
.read_event_value = &tsl2x7x_read_thresh,
|
||||
.write_event_value = &tsl2x7x_write_thresh,
|
||||
.read_event_config = &tsl2x7x_read_interrupt_config,
|
||||
.write_event_config = &tsl2x7x_write_interrupt_config,
|
||||
.read_event_value_new = &tsl2x7x_read_thresh,
|
||||
.write_event_value_new = &tsl2x7x_write_thresh,
|
||||
.read_event_config_new = &tsl2x7x_read_interrupt_config,
|
||||
.write_event_config_new = &tsl2x7x_write_interrupt_config,
|
||||
},
|
||||
[ALSPRX] = {
|
||||
.attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX],
|
||||
|
@ -1689,10 +1694,10 @@ static const struct iio_info tsl2X7X_device_info[] = {
|
|||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &tsl2x7x_read_raw,
|
||||
.write_raw = &tsl2x7x_write_raw,
|
||||
.read_event_value = &tsl2x7x_read_thresh,
|
||||
.write_event_value = &tsl2x7x_write_thresh,
|
||||
.read_event_config = &tsl2x7x_read_interrupt_config,
|
||||
.write_event_config = &tsl2x7x_write_interrupt_config,
|
||||
.read_event_value_new = &tsl2x7x_read_thresh,
|
||||
.write_event_value_new = &tsl2x7x_write_thresh,
|
||||
.read_event_config_new = &tsl2x7x_read_interrupt_config,
|
||||
.write_event_config_new = &tsl2x7x_write_interrupt_config,
|
||||
},
|
||||
[PRX2] = {
|
||||
.attrs = &tsl2X7X_device_attr_group_tbl[PRX2],
|
||||
|
@ -1700,10 +1705,10 @@ static const struct iio_info tsl2X7X_device_info[] = {
|
|||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &tsl2x7x_read_raw,
|
||||
.write_raw = &tsl2x7x_write_raw,
|
||||
.read_event_value = &tsl2x7x_read_thresh,
|
||||
.write_event_value = &tsl2x7x_write_thresh,
|
||||
.read_event_config = &tsl2x7x_read_interrupt_config,
|
||||
.write_event_config = &tsl2x7x_write_interrupt_config,
|
||||
.read_event_value_new = &tsl2x7x_read_thresh,
|
||||
.write_event_value_new = &tsl2x7x_write_thresh,
|
||||
.read_event_config_new = &tsl2x7x_read_interrupt_config,
|
||||
.write_event_config_new = &tsl2x7x_write_interrupt_config,
|
||||
},
|
||||
[ALSPRX2] = {
|
||||
.attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2],
|
||||
|
@ -1711,10 +1716,24 @@ static const struct iio_info tsl2X7X_device_info[] = {
|
|||
.driver_module = THIS_MODULE,
|
||||
.read_raw = &tsl2x7x_read_raw,
|
||||
.write_raw = &tsl2x7x_write_raw,
|
||||
.read_event_value = &tsl2x7x_read_thresh,
|
||||
.write_event_value = &tsl2x7x_write_thresh,
|
||||
.read_event_config = &tsl2x7x_read_interrupt_config,
|
||||
.write_event_config = &tsl2x7x_write_interrupt_config,
|
||||
.read_event_value_new = &tsl2x7x_read_thresh,
|
||||
.write_event_value_new = &tsl2x7x_write_thresh,
|
||||
.read_event_config_new = &tsl2x7x_read_interrupt_config,
|
||||
.write_event_config_new = &tsl2x7x_write_interrupt_config,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct iio_event_spec tsl2x7x_events[] = {
|
||||
{
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_RISING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
}, {
|
||||
.type = IIO_EV_TYPE_THRESH,
|
||||
.dir = IIO_EV_DIR_FALLING,
|
||||
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
||||
BIT(IIO_EV_INFO_ENABLE),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1733,7 +1752,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
|
|||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE) |
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS),
|
||||
.event_mask = TSL2X7X_EVENT_MASK
|
||||
.event_spec = tsl2x7x_events,
|
||||
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
|
||||
}, {
|
||||
.type = IIO_INTENSITY,
|
||||
.indexed = 1,
|
||||
|
@ -1750,7 +1770,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
|
|||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.event_mask = TSL2X7X_EVENT_MASK
|
||||
.event_spec = tsl2x7x_events,
|
||||
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
|
||||
},
|
||||
},
|
||||
.chan_table_elements = 1,
|
||||
|
@ -1770,7 +1791,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
|
|||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE) |
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS),
|
||||
.event_mask = TSL2X7X_EVENT_MASK
|
||||
.event_spec = tsl2x7x_events,
|
||||
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
|
||||
}, {
|
||||
.type = IIO_INTENSITY,
|
||||
.indexed = 1,
|
||||
|
@ -1781,7 +1803,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
|
|||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||
.event_mask = TSL2X7X_EVENT_MASK
|
||||
.event_spec = tsl2x7x_events,
|
||||
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
|
||||
},
|
||||
},
|
||||
.chan_table_elements = 4,
|
||||
|
@ -1795,7 +1818,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
|
|||
.channel = 0,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE),
|
||||
.event_mask = TSL2X7X_EVENT_MASK
|
||||
.event_spec = tsl2x7x_events,
|
||||
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
|
||||
},
|
||||
},
|
||||
.chan_table_elements = 1,
|
||||
|
@ -1815,7 +1839,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
|
|||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE) |
|
||||
BIT(IIO_CHAN_INFO_CALIBBIAS),
|
||||
.event_mask = TSL2X7X_EVENT_MASK
|
||||
.event_spec = tsl2x7x_events,
|
||||
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
|
||||
}, {
|
||||
.type = IIO_INTENSITY,
|
||||
.indexed = 1,
|
||||
|
@ -1827,7 +1852,8 @@ static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
|
|||
.channel = 0,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_CALIBSCALE),
|
||||
.event_mask = TSL2X7X_EVENT_MASK
|
||||
.event_spec = tsl2x7x_events,
|
||||
.num_event_specs = ARRAY_SIZE(tsl2x7x_events),
|
||||
},
|
||||
},
|
||||
.chan_table_elements = 4,
|
||||
|
|
|
@ -23,18 +23,17 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define HMC5843_CONFIG_REG_A 0x00
|
||||
#define HMC5843_CONFIG_REG_B 0x01
|
||||
#define HMC5843_MODE_REG 0x02
|
||||
#define HMC5843_DATA_OUT_X_MSB_REG 0x03
|
||||
#define HMC5843_DATA_OUT_Y_MSB_REG 0x05
|
||||
#define HMC5843_DATA_OUT_Z_MSB_REG 0x07
|
||||
/* Beware: Y and Z are exchanged on HMC5883 */
|
||||
#define HMC5883_DATA_OUT_Z_MSB_REG 0x05
|
||||
#define HMC5883_DATA_OUT_Y_MSB_REG 0x07
|
||||
#define HMC5843_DATA_OUT_MSB_REGS 0x03
|
||||
#define HMC5843_STATUS_REG 0x09
|
||||
#define HMC5843_ID_REG 0x0a
|
||||
|
||||
enum hmc5843_ids {
|
||||
HMC5843_ID,
|
||||
|
@ -49,7 +48,7 @@ enum hmc5843_ids {
|
|||
*/
|
||||
#define HMC5843_RANGE_GAIN_OFFSET 0x05
|
||||
#define HMC5843_RANGE_GAIN_DEFAULT 0x01
|
||||
#define HMC5843_RANGE_GAIN_MAX 0x07
|
||||
#define HMC5843_RANGE_GAINS 8
|
||||
|
||||
/* Device status */
|
||||
#define HMC5843_DATA_READY 0x01
|
||||
|
@ -68,75 +67,27 @@ enum hmc5843_ids {
|
|||
*/
|
||||
#define HMC5843_RATE_OFFSET 0x02
|
||||
#define HMC5843_RATE_DEFAULT 0x04
|
||||
#define HMC5843_RATE_BITMASK 0x1C
|
||||
#define HMC5843_RATE_NOT_USED 0x07
|
||||
#define HMC5843_RATES 7
|
||||
|
||||
/* Device measurement configuration */
|
||||
#define HMC5843_MEAS_CONF_NORMAL 0x00
|
||||
#define HMC5843_MEAS_CONF_POSITIVE_BIAS 0x01
|
||||
#define HMC5843_MEAS_CONF_NEGATIVE_BIAS 0x02
|
||||
#define HMC5843_MEAS_CONF_NOT_USED 0x03
|
||||
#define HMC5843_MEAS_CONF_MASK 0x03
|
||||
|
||||
/* Scaling factors: 10000000/Gain */
|
||||
static const int hmc5843_regval_to_nanoscale[] = {
|
||||
static const int hmc5843_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
|
||||
6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714
|
||||
};
|
||||
|
||||
static const int hmc5883_regval_to_nanoscale[] = {
|
||||
static const int hmc5883_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
|
||||
7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662
|
||||
};
|
||||
|
||||
static const int hmc5883l_regval_to_nanoscale[] = {
|
||||
static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
|
||||
7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478
|
||||
};
|
||||
|
||||
/*
|
||||
* From the HMC5843 datasheet:
|
||||
* Value | Sensor input field range (Ga) | Gain (counts/milli-Gauss)
|
||||
* 0 | (+-)0.7 | 1620
|
||||
* 1 | (+-)1.0 | 1300
|
||||
* 2 | (+-)1.5 | 970
|
||||
* 3 | (+-)2.0 | 780
|
||||
* 4 | (+-)3.2 | 530
|
||||
* 5 | (+-)3.8 | 460
|
||||
* 6 | (+-)4.5 | 390
|
||||
* 7 | (+-)6.5 | 280
|
||||
*
|
||||
* From the HMC5883 datasheet:
|
||||
* Value | Recommended sensor field range (Ga) | Gain (counts/Gauss)
|
||||
* 0 | (+-)0.9 | 1280
|
||||
* 1 | (+-)1.2 | 1024
|
||||
* 2 | (+-)1.9 | 768
|
||||
* 3 | (+-)2.5 | 614
|
||||
* 4 | (+-)4.0 | 415
|
||||
* 5 | (+-)4.6 | 361
|
||||
* 6 | (+-)5.5 | 307
|
||||
* 7 | (+-)7.9 | 219
|
||||
*
|
||||
* From the HMC5883L datasheet:
|
||||
* Value | Recommended sensor field range (Ga) | Gain (LSB/Gauss)
|
||||
* 0 | (+-)0.88 | 1370
|
||||
* 1 | (+-)1.3 | 1090
|
||||
* 2 | (+-)1.9 | 820
|
||||
* 3 | (+-)2.5 | 660
|
||||
* 4 | (+-)4.0 | 440
|
||||
* 5 | (+-)4.7 | 390
|
||||
* 6 | (+-)5.6 | 330
|
||||
* 7 | (+-)8.1 | 230
|
||||
*/
|
||||
static const int hmc5843_regval_to_input_field_mga[] = {
|
||||
700, 1000, 1500, 2000, 3200, 3800, 4500, 6500
|
||||
};
|
||||
|
||||
static const int hmc5883_regval_to_input_field_mga[] = {
|
||||
900, 1200, 1900, 2500, 4000, 4600, 5500, 7900
|
||||
};
|
||||
|
||||
static const int hmc5883l_regval_to_input_field_mga[] = {
|
||||
880, 1300, 1900, 2500, 4000, 4700, 5600, 8100
|
||||
};
|
||||
|
||||
/*
|
||||
* From the datasheet:
|
||||
* Value | HMC5843 | HMC5883/HMC5883L
|
||||
|
@ -163,7 +114,6 @@ static const int hmc5883_regval_to_samp_freq[7][2] = {
|
|||
struct hmc5843_chip_info {
|
||||
const struct iio_chan_spec *channels;
|
||||
const int (*regval_to_samp_freq)[2];
|
||||
const int *regval_to_input_field_mga;
|
||||
const int *regval_to_nanoscale;
|
||||
};
|
||||
|
||||
|
@ -176,28 +126,34 @@ struct hmc5843_data {
|
|||
u8 operating_mode;
|
||||
u8 range;
|
||||
const struct hmc5843_chip_info *variant;
|
||||
__be16 buffer[8]; /* 3x 16-bit channels + padding + 64-bit timestamp */
|
||||
};
|
||||
|
||||
/* The lower two bits contain the current conversion mode */
|
||||
static s32 hmc5843_configure(struct i2c_client *client,
|
||||
u8 operating_mode)
|
||||
static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode)
|
||||
{
|
||||
return i2c_smbus_write_byte_data(client,
|
||||
HMC5843_MODE_REG,
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = i2c_smbus_write_byte_data(data->client, HMC5843_MODE_REG,
|
||||
operating_mode & HMC5843_MODE_MASK);
|
||||
if (ret >= 0)
|
||||
data->operating_mode = operating_mode;
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return the measurement value from the specified channel */
|
||||
static int hmc5843_read_measurement(struct hmc5843_data *data,
|
||||
int address, int *val)
|
||||
static int hmc5843_wait_measurement(struct hmc5843_data *data)
|
||||
{
|
||||
s32 result;
|
||||
int tries = 150;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
while (tries-- > 0) {
|
||||
result = i2c_smbus_read_byte_data(data->client,
|
||||
HMC5843_STATUS_REG);
|
||||
if (result < 0)
|
||||
return result;
|
||||
if (result & HMC5843_DATA_READY)
|
||||
break;
|
||||
msleep(20);
|
||||
|
@ -205,86 +161,35 @@ static int hmc5843_read_measurement(struct hmc5843_data *data,
|
|||
|
||||
if (tries < 0) {
|
||||
dev_err(&data->client->dev, "data not ready\n");
|
||||
mutex_unlock(&data->lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
result = i2c_smbus_read_word_swapped(data->client, address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the measurement value from the specified channel */
|
||||
static int hmc5843_read_measurement(struct hmc5843_data *data,
|
||||
int idx, int *val)
|
||||
{
|
||||
s32 result;
|
||||
__be16 values[3];
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
result = hmc5843_wait_measurement(data);
|
||||
if (result < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
return result;
|
||||
}
|
||||
result = i2c_smbus_read_i2c_block_data(data->client,
|
||||
HMC5843_DATA_OUT_MSB_REGS, sizeof(values), (u8 *) values);
|
||||
mutex_unlock(&data->lock);
|
||||
if (result < 0)
|
||||
return -EINVAL;
|
||||
|
||||
*val = sign_extend32(result, 15);
|
||||
*val = sign_extend32(be16_to_cpu(values[idx]), 15);
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
/*
|
||||
* From the datasheet:
|
||||
* 0 - Continuous-Conversion Mode: In continuous-conversion mode, the
|
||||
* device continuously performs conversions and places the result in
|
||||
* the data register.
|
||||
*
|
||||
* 1 - Single-Conversion Mode : Device performs a single measurement,
|
||||
* sets RDY high and returns to sleep mode.
|
||||
*
|
||||
* 2 - Idle Mode : Device is placed in idle mode.
|
||||
*
|
||||
* 3 - Sleep Mode : Device is placed in sleep mode.
|
||||
*
|
||||
*/
|
||||
static ssize_t hmc5843_show_operating_mode(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
return sprintf(buf, "%d\n", data->operating_mode);
|
||||
}
|
||||
|
||||
static ssize_t hmc5843_set_operating_mode(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
unsigned long operating_mode = 0;
|
||||
s32 status;
|
||||
int error;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
error = kstrtoul(buf, 10, &operating_mode);
|
||||
if (error) {
|
||||
count = error;
|
||||
goto exit;
|
||||
}
|
||||
dev_dbg(dev, "set conversion mode to %lu\n", operating_mode);
|
||||
if (operating_mode > HMC5843_MODE_SLEEP) {
|
||||
count = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = i2c_smbus_write_byte_data(client, this_attr->address,
|
||||
operating_mode);
|
||||
if (status) {
|
||||
count = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
data->operating_mode = operating_mode;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR(operating_mode,
|
||||
S_IWUSR | S_IRUGO,
|
||||
hmc5843_show_operating_mode,
|
||||
hmc5843_set_operating_mode,
|
||||
HMC5843_MODE_REG);
|
||||
|
||||
/*
|
||||
* API for setting the measurement configuration to
|
||||
* Normal, Positive bias and Negative bias
|
||||
|
@ -305,19 +210,24 @@ static IIO_DEVICE_ATTR(operating_mode,
|
|||
*/
|
||||
static s32 hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf)
|
||||
{
|
||||
u8 reg_val;
|
||||
reg_val = (meas_conf & HMC5843_MEAS_CONF_MASK) |
|
||||
(data->rate << HMC5843_RATE_OFFSET);
|
||||
return i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A,
|
||||
reg_val);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A,
|
||||
(meas_conf & HMC5843_MEAS_CONF_MASK) |
|
||||
(data->rate << HMC5843_RATE_OFFSET));
|
||||
if (ret >= 0)
|
||||
data->meas_conf = meas_conf;
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t hmc5843_show_measurement_configuration(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
|
||||
return sprintf(buf, "%d\n", data->meas_conf);
|
||||
}
|
||||
|
||||
|
@ -326,28 +236,19 @@ static ssize_t hmc5843_set_measurement_configuration(struct device *dev,
|
|||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
|
||||
unsigned long meas_conf = 0;
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
error = kstrtoul(buf, 10, &meas_conf);
|
||||
if (error)
|
||||
return error;
|
||||
if (meas_conf >= HMC5843_MEAS_CONF_NOT_USED)
|
||||
ret = kstrtoul(buf, 10, &meas_conf);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (meas_conf >= HMC5843_MEAS_CONF_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
dev_dbg(dev, "set measurement configuration to %lu\n", meas_conf);
|
||||
if (hmc5843_set_meas_conf(data, meas_conf)) {
|
||||
count = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
data->meas_conf = meas_conf;
|
||||
ret = hmc5843_set_meas_conf(data, meas_conf);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->lock);
|
||||
return count;
|
||||
return (ret < 0) ? ret : count;
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR(meas_conf,
|
||||
|
@ -356,15 +257,17 @@ static IIO_DEVICE_ATTR(meas_conf,
|
|||
hmc5843_set_measurement_configuration,
|
||||
0);
|
||||
|
||||
static ssize_t hmc5843_show_int_plus_micros(char *buf,
|
||||
const int (*vals)[2], int n)
|
||||
static ssize_t hmc5843_show_samp_freq_avail(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
|
||||
size_t len = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
for (i = 0; i < HMC5843_RATES; i++)
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len,
|
||||
"%d.%d ", vals[i][0], vals[i][1]);
|
||||
"%d.%d ", data->variant->regval_to_samp_freq[i][0],
|
||||
data->variant->regval_to_samp_freq[i][1]);
|
||||
|
||||
/* replace trailing space by newline */
|
||||
buf[len - 1] = '\n';
|
||||
|
@ -372,98 +275,84 @@ static ssize_t hmc5843_show_int_plus_micros(char *buf,
|
|||
return len;
|
||||
}
|
||||
|
||||
static int hmc5843_check_int_plus_micros(const int (*vals)[2], int n,
|
||||
int val, int val2)
|
||||
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_samp_freq_avail);
|
||||
|
||||
static int hmc5843_set_samp_freq(struct hmc5843_data *data, u8 rate)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A,
|
||||
data->meas_conf | (rate << HMC5843_RATE_OFFSET));
|
||||
if (ret >= 0)
|
||||
data->rate = rate;
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hmc5843_get_samp_freq_index(struct hmc5843_data *data,
|
||||
int val, int val2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (val == vals[i][0] && val2 == vals[i][1])
|
||||
for (i = 0; i < HMC5843_RATES; i++)
|
||||
if (val == data->variant->regval_to_samp_freq[i][0] &&
|
||||
val2 == data->variant->regval_to_samp_freq[i][1])
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static ssize_t hmc5843_show_samp_freq_avail(struct device *dev,
|
||||
static int hmc5843_set_range_gain(struct hmc5843_data *data, u8 range)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_B,
|
||||
range << HMC5843_RANGE_GAIN_OFFSET);
|
||||
if (ret >= 0)
|
||||
data->range = range;
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t hmc5843_show_scale_avail(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
|
||||
|
||||
return hmc5843_show_int_plus_micros(buf,
|
||||
data->variant->regval_to_samp_freq, HMC5843_RATE_NOT_USED);
|
||||
size_t len = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < HMC5843_RANGE_GAINS; i++)
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len,
|
||||
"0.%09d ", data->variant->regval_to_nanoscale[i]);
|
||||
|
||||
/* replace trailing space by newline */
|
||||
buf[len - 1] = '\n';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_samp_freq_avail);
|
||||
static IIO_DEVICE_ATTR(scale_available, S_IRUGO,
|
||||
hmc5843_show_scale_avail, NULL, 0);
|
||||
|
||||
static s32 hmc5843_set_rate(struct hmc5843_data *data, u8 rate)
|
||||
static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2)
|
||||
{
|
||||
u8 reg_val = data->meas_conf | (rate << HMC5843_RATE_OFFSET);
|
||||
int i;
|
||||
|
||||
return i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A,
|
||||
reg_val);
|
||||
if (val != 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < HMC5843_RANGE_GAINS; i++)
|
||||
if (val2 == data->variant->regval_to_nanoscale[i])
|
||||
return i;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int hmc5843_check_samp_freq(struct hmc5843_data *data,
|
||||
int val, int val2)
|
||||
{
|
||||
return hmc5843_check_int_plus_micros(
|
||||
data->variant->regval_to_samp_freq, HMC5843_RATE_NOT_USED,
|
||||
val, val2);
|
||||
}
|
||||
|
||||
static ssize_t hmc5843_show_range_gain(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
u8 range;
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
|
||||
range = data->range;
|
||||
return sprintf(buf, "%d\n", data->variant->regval_to_input_field_mga[range]);
|
||||
}
|
||||
|
||||
static ssize_t hmc5843_set_range_gain(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
unsigned long range = 0;
|
||||
int error;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
error = kstrtoul(buf, 10, &range);
|
||||
if (error) {
|
||||
count = error;
|
||||
goto exit;
|
||||
}
|
||||
dev_dbg(dev, "set range to %lu\n", range);
|
||||
|
||||
if (range > HMC5843_RANGE_GAIN_MAX) {
|
||||
count = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data->range = range;
|
||||
range = range << HMC5843_RANGE_GAIN_OFFSET;
|
||||
if (i2c_smbus_write_byte_data(data->client, this_attr->address, range))
|
||||
count = -EINVAL;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR(in_magn_range,
|
||||
S_IWUSR | S_IRUGO,
|
||||
hmc5843_show_range_gain,
|
||||
hmc5843_set_range_gain,
|
||||
HMC5843_CONFIG_REG_B);
|
||||
|
||||
static int hmc5843_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
|
@ -472,7 +361,7 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev,
|
|||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
return hmc5843_read_measurement(data, chan->address, val);
|
||||
return hmc5843_read_measurement(data, chan->scan_index, val);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
*val2 = data->variant->regval_to_nanoscale[data->range];
|
||||
|
@ -490,27 +379,70 @@ static int hmc5843_write_raw(struct iio_dev *indio_dev,
|
|||
int val, int val2, long mask)
|
||||
{
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
int ret, rate;
|
||||
int rate, range;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
rate = hmc5843_check_samp_freq(data, val, val2);
|
||||
rate = hmc5843_get_samp_freq_index(data, val, val2);
|
||||
if (rate < 0)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = hmc5843_set_rate(data, rate);
|
||||
if (ret >= 0)
|
||||
data->rate = rate;
|
||||
mutex_unlock(&data->lock);
|
||||
return hmc5843_set_samp_freq(data, rate);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
range = hmc5843_get_scale_index(data, val, val2);
|
||||
if (range < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return ret;
|
||||
return hmc5843_set_range_gain(data, range);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
#define HMC5843_CHANNEL(axis, addr) \
|
||||
static int hmc5843_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return IIO_VAL_INT_PLUS_MICRO;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t hmc5843_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct hmc5843_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = hmc5843_wait_measurement(data);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(data->client,
|
||||
HMC5843_DATA_OUT_MSB_REGS, 3 * sizeof(__be16),
|
||||
(u8 *) data->buffer);
|
||||
mutex_unlock(&data->lock);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
||||
iio_get_time_ns());
|
||||
|
||||
done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#define HMC5843_CHANNEL(axis, idx) \
|
||||
{ \
|
||||
.type = IIO_MAGN, \
|
||||
.modified = 1, \
|
||||
|
@ -518,25 +450,28 @@ static int hmc5843_write_raw(struct iio_dev *indio_dev,
|
|||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.address = addr \
|
||||
.scan_index = idx, \
|
||||
.scan_type = IIO_ST('s', 16, 16, IIO_BE), \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec hmc5843_channels[] = {
|
||||
HMC5843_CHANNEL(X, HMC5843_DATA_OUT_X_MSB_REG),
|
||||
HMC5843_CHANNEL(Y, HMC5843_DATA_OUT_Y_MSB_REG),
|
||||
HMC5843_CHANNEL(Z, HMC5843_DATA_OUT_Z_MSB_REG),
|
||||
HMC5843_CHANNEL(X, 0),
|
||||
HMC5843_CHANNEL(Y, 1),
|
||||
HMC5843_CHANNEL(Z, 2),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
};
|
||||
|
||||
/* Beware: Y and Z are exchanged on HMC5883 */
|
||||
static const struct iio_chan_spec hmc5883_channels[] = {
|
||||
HMC5843_CHANNEL(X, HMC5843_DATA_OUT_X_MSB_REG),
|
||||
HMC5843_CHANNEL(Y, HMC5883_DATA_OUT_Y_MSB_REG),
|
||||
HMC5843_CHANNEL(Z, HMC5883_DATA_OUT_Z_MSB_REG),
|
||||
HMC5843_CHANNEL(X, 0),
|
||||
HMC5843_CHANNEL(Z, 1),
|
||||
HMC5843_CHANNEL(Y, 2),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
};
|
||||
|
||||
static struct attribute *hmc5843_attributes[] = {
|
||||
&iio_dev_attr_meas_conf.dev_attr.attr,
|
||||
&iio_dev_attr_operating_mode.dev_attr.attr,
|
||||
&iio_dev_attr_in_magn_range.dev_attr.attr,
|
||||
&iio_dev_attr_scale_available.dev_attr.attr,
|
||||
&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
@ -549,48 +484,62 @@ static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
|
|||
[HMC5843_ID] = {
|
||||
.channels = hmc5843_channels,
|
||||
.regval_to_samp_freq = hmc5843_regval_to_samp_freq,
|
||||
.regval_to_input_field_mga =
|
||||
hmc5843_regval_to_input_field_mga,
|
||||
.regval_to_nanoscale = hmc5843_regval_to_nanoscale,
|
||||
},
|
||||
[HMC5883_ID] = {
|
||||
.channels = hmc5883_channels,
|
||||
.regval_to_samp_freq = hmc5883_regval_to_samp_freq,
|
||||
.regval_to_input_field_mga =
|
||||
hmc5883_regval_to_input_field_mga,
|
||||
.regval_to_nanoscale = hmc5883_regval_to_nanoscale,
|
||||
},
|
||||
[HMC5883L_ID] = {
|
||||
.channels = hmc5883_channels,
|
||||
.regval_to_samp_freq = hmc5883_regval_to_samp_freq,
|
||||
.regval_to_input_field_mga =
|
||||
hmc5883l_regval_to_input_field_mga,
|
||||
.regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
|
||||
},
|
||||
};
|
||||
|
||||
static void hmc5843_init(struct hmc5843_data *data)
|
||||
static int hmc5843_init(struct hmc5843_data *data)
|
||||
{
|
||||
hmc5843_set_meas_conf(data, HMC5843_MEAS_CONF_NORMAL);
|
||||
hmc5843_set_rate(data, HMC5843_RATE_DEFAULT);
|
||||
hmc5843_configure(data->client, HMC5843_MODE_CONVERSION_CONTINUOUS);
|
||||
i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_B,
|
||||
HMC5843_RANGE_GAIN_DEFAULT);
|
||||
int ret;
|
||||
u8 id[3];
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(data->client, HMC5843_ID_REG,
|
||||
sizeof(id), id);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (id[0] != 'H' || id[1] != '4' || id[2] != '3') {
|
||||
dev_err(&data->client->dev, "no HMC5843/5883/5883L sensor\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = hmc5843_set_meas_conf(data, HMC5843_MEAS_CONF_NORMAL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = hmc5843_set_samp_freq(data, HMC5843_RATE_DEFAULT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = hmc5843_set_range_gain(data, HMC5843_RANGE_GAIN_DEFAULT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS);
|
||||
}
|
||||
|
||||
static const struct iio_info hmc5843_info = {
|
||||
.attrs = &hmc5843_group,
|
||||
.read_raw = &hmc5843_read_raw,
|
||||
.write_raw = &hmc5843_write_raw,
|
||||
.write_raw_get_fmt = &hmc5843_write_raw_get_fmt,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const unsigned long hmc5843_scan_masks[] = {0x7, 0};
|
||||
|
||||
static int hmc5843_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct hmc5843_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int err = 0;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
|
||||
if (indio_dev == NULL)
|
||||
|
@ -608,22 +557,38 @@ static int hmc5843_probe(struct i2c_client *client,
|
|||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = data->variant->channels;
|
||||
indio_dev->num_channels = 3;
|
||||
indio_dev->num_channels = 4;
|
||||
indio_dev->available_scan_masks = hmc5843_scan_masks;
|
||||
|
||||
hmc5843_init(data);
|
||||
ret = hmc5843_init(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
err = iio_device_register(indio_dev);
|
||||
if (err)
|
||||
return err;
|
||||
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
||||
hmc5843_trigger_handler, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0)
|
||||
goto buffer_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
buffer_cleanup:
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hmc5843_remove(struct i2c_client *client)
|
||||
{
|
||||
iio_device_unregister(i2c_get_clientdata(client));
|
||||
/* sleep mode to save power */
|
||||
hmc5843_configure(client, HMC5843_MODE_SLEEP);
|
||||
struct iio_dev *indio_dev = i2c_get_clientdata(client);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_triggered_buffer_cleanup(indio_dev);
|
||||
|
||||
/* sleep mode to save power */
|
||||
hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -631,9 +596,10 @@ static int hmc5843_remove(struct i2c_client *client)
|
|||
#ifdef CONFIG_PM_SLEEP
|
||||
static int hmc5843_suspend(struct device *dev)
|
||||
{
|
||||
hmc5843_configure(to_i2c_client(dev), HMC5843_MODE_SLEEP);
|
||||
struct hmc5843_data *data = iio_priv(i2c_get_clientdata(
|
||||
to_i2c_client(dev)));
|
||||
|
||||
return 0;
|
||||
return hmc5843_set_mode(data, HMC5843_MODE_SLEEP);
|
||||
}
|
||||
|
||||
static int hmc5843_resume(struct device *dev)
|
||||
|
@ -641,9 +607,7 @@ static int hmc5843_resume(struct device *dev)
|
|||
struct hmc5843_data *data = iio_priv(i2c_get_clientdata(
|
||||
to_i2c_client(dev)));
|
||||
|
||||
hmc5843_configure(data->client, data->operating_mode);
|
||||
|
||||
return 0;
|
||||
return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_suspend, hmc5843_resume);
|
||||
|
|
|
@ -87,15 +87,10 @@ static int ade7758_ring_preenable(struct iio_dev *indio_dev)
|
|||
{
|
||||
struct ade7758_state *st = iio_priv(indio_dev);
|
||||
unsigned channel;
|
||||
int ret;
|
||||
|
||||
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
|
||||
return -EINVAL;
|
||||
|
||||
ret = iio_sw_buffer_preenable(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
channel = find_first_bit(indio_dev->active_scan_mask,
|
||||
indio_dev->masklength);
|
||||
|
||||
|
@ -121,14 +116,17 @@ void ade7758_unconfigure_ring(struct iio_dev *indio_dev)
|
|||
int ade7758_configure_ring(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct ade7758_state *st = iio_priv(indio_dev);
|
||||
struct iio_buffer *buffer;
|
||||
int ret = 0;
|
||||
|
||||
indio_dev->buffer = iio_kfifo_allocate(indio_dev);
|
||||
if (!indio_dev->buffer) {
|
||||
buffer = iio_kfifo_allocate(indio_dev);
|
||||
if (!buffer) {
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
iio_device_attach_buffer(indio_dev, buffer);
|
||||
|
||||
indio_dev->setup_ops = &ade7758_ring_setup_ops;
|
||||
|
||||
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define _IIO_BUFFER_GENERIC_H_
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/kref.h>
|
||||
|
||||
#ifdef CONFIG_IIO_BUFFER
|
||||
|
||||
|
@ -26,6 +27,8 @@ struct iio_buffer;
|
|||
* @set_bytes_per_datum:set number of bytes per datum
|
||||
* @get_length: get number of datums in buffer
|
||||
* @set_length: set number of datums in buffer
|
||||
* @release: called when the last reference to the buffer is dropped,
|
||||
* should free all resources allocated by the buffer.
|
||||
*
|
||||
* The purpose of this structure is to make the buffer element
|
||||
* modular as event for a given driver, different usecases may require
|
||||
|
@ -47,6 +50,8 @@ struct iio_buffer_access_funcs {
|
|||
int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
|
||||
int (*get_length)(struct iio_buffer *buffer);
|
||||
int (*set_length)(struct iio_buffer *buffer, int length);
|
||||
|
||||
void (*release)(struct iio_buffer *buffer);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -67,6 +72,7 @@ struct iio_buffer_access_funcs {
|
|||
* @demux_list: [INTERN] list of operations required to demux the scan.
|
||||
* @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
|
||||
* @buffer_list: [INTERN] entry in the devices list of current buffers.
|
||||
* @ref: [INTERN] reference count of the buffer.
|
||||
*/
|
||||
struct iio_buffer {
|
||||
int length;
|
||||
|
@ -83,6 +89,7 @@ struct iio_buffer {
|
|||
struct list_head demux_list;
|
||||
void *demux_bounce;
|
||||
struct list_head buffer_list;
|
||||
struct kref ref;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -199,11 +206,27 @@ ssize_t iio_buffer_show_enable(struct device *dev,
|
|||
iio_buffer_show_enable, \
|
||||
iio_buffer_store_enable)
|
||||
|
||||
int iio_sw_buffer_preenable(struct iio_dev *indio_dev);
|
||||
|
||||
bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
|
||||
const unsigned long *mask);
|
||||
|
||||
struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer);
|
||||
void iio_buffer_put(struct iio_buffer *buffer);
|
||||
|
||||
/**
|
||||
* iio_device_attach_buffer - Attach a buffer to a IIO device
|
||||
* @indio_dev: The device the buffer should be attached to
|
||||
* @buffer: The buffer to attach to the device
|
||||
*
|
||||
* This function attaches a buffer to a IIO device. The buffer stays attached to
|
||||
* the device until the device is freed. The function should only be called at
|
||||
* most once per device.
|
||||
*/
|
||||
static inline void iio_device_attach_buffer(struct iio_dev *indio_dev,
|
||||
struct iio_buffer *buffer)
|
||||
{
|
||||
indio_dev->buffer = iio_buffer_get(buffer);
|
||||
}
|
||||
|
||||
#else /* CONFIG_IIO_BUFFER */
|
||||
|
||||
static inline int iio_buffer_register(struct iio_dev *indio_dev,
|
||||
|
@ -216,6 +239,9 @@ static inline int iio_buffer_register(struct iio_dev *indio_dev,
|
|||
static inline void iio_buffer_unregister(struct iio_dev *indio_dev)
|
||||
{}
|
||||
|
||||
static inline void iio_buffer_get(struct iio_buffer *buffer) {}
|
||||
static inline void iio_buffer_put(struct iio_buffer *buffer) {}
|
||||
|
||||
#endif /* CONFIG_IIO_BUFFER */
|
||||
|
||||
#endif /* _IIO_BUFFER_GENERIC_H_ */
|
||||
|
|
|
@ -26,20 +26,6 @@ struct iio_event_data {
|
|||
|
||||
#define IIO_GET_EVENT_FD_IOCTL _IOR('i', 0x90, int)
|
||||
|
||||
enum iio_event_type {
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_TYPE_MAG,
|
||||
IIO_EV_TYPE_ROC,
|
||||
IIO_EV_TYPE_THRESH_ADAPTIVE,
|
||||
IIO_EV_TYPE_MAG_ADAPTIVE,
|
||||
};
|
||||
|
||||
enum iio_event_direction {
|
||||
IIO_EV_DIR_EITHER,
|
||||
IIO_EV_DIR_RISING,
|
||||
IIO_EV_DIR_FALLING,
|
||||
};
|
||||
|
||||
/**
|
||||
* IIO_EVENT_CODE() - create event identifier
|
||||
* @chan_type: Type of the channel. Should be one of enum iio_chan_type.
|
||||
|
|
|
@ -138,6 +138,29 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
|
|||
.private = (uintptr_t)(_e), \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct iio_event_spec - specification for a channel event
|
||||
* @type: Type of the event
|
||||
* @dir: Direction of the event
|
||||
* @mask_separate: Bit mask of enum iio_event_info values. Attributes
|
||||
* set in this mask will be registered per channel.
|
||||
* @mask_shared_by_type: Bit mask of enum iio_event_info values. Attributes
|
||||
* set in this mask will be shared by channel type.
|
||||
* @mask_shared_by_dir: Bit mask of enum iio_event_info values. Attributes
|
||||
* set in this mask will be shared by channel type and
|
||||
* direction.
|
||||
* @mask_shared_by_all: Bit mask of enum iio_event_info values. Attributes
|
||||
* set in this mask will be shared by all channels.
|
||||
*/
|
||||
struct iio_event_spec {
|
||||
enum iio_event_type type;
|
||||
enum iio_event_direction dir;
|
||||
unsigned long mask_separate;
|
||||
unsigned long mask_shared_by_type;
|
||||
unsigned long mask_shared_by_dir;
|
||||
unsigned long mask_shared_by_all;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iio_chan_spec - specification of a single channel
|
||||
* @type: What type of measurement is the channel making.
|
||||
|
@ -163,6 +186,9 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev,
|
|||
* @info_mask_shared_by_all: What information is to be exported that is shared
|
||||
* by all channels.
|
||||
* @event_mask: What events can this channel produce.
|
||||
* @event_spec: Array of events which should be registered for this
|
||||
* channel.
|
||||
* @num_event_specs: Size of the event_spec array.
|
||||
* @ext_info: Array of extended info attributes for this channel.
|
||||
* The array is NULL terminated, the last element should
|
||||
* have its name field set to NULL.
|
||||
|
@ -201,6 +227,8 @@ struct iio_chan_spec {
|
|||
long info_mask_shared_by_dir;
|
||||
long info_mask_shared_by_all;
|
||||
long event_mask;
|
||||
const struct iio_event_spec *event_spec;
|
||||
unsigned int num_event_specs;
|
||||
const struct iio_chan_spec_ext_info *ext_info;
|
||||
const char *extend_name;
|
||||
const char *datasheet_name;
|
||||
|
@ -283,6 +311,12 @@ struct iio_dev;
|
|||
* is event dependant. event_code specifies which event.
|
||||
* @write_event_value: write the value associated with the event.
|
||||
* Meaning is event dependent.
|
||||
* @read_event_config_new: find out if the event is enabled. New style interface.
|
||||
* @write_event_config_new: set if the event is enabled. New style interface.
|
||||
* @read_event_value_new: read a configuration value associated with the event.
|
||||
* New style interface.
|
||||
* @write_event_value_new: write a configuration value for the event. New style
|
||||
* interface.
|
||||
* @validate_trigger: function to validate the trigger when the
|
||||
* current trigger gets changed.
|
||||
* @update_scan_mode: function to configure device and scan buffer when
|
||||
|
@ -323,6 +357,30 @@ struct iio_info {
|
|||
int (*write_event_value)(struct iio_dev *indio_dev,
|
||||
u64 event_code,
|
||||
int val);
|
||||
|
||||
int (*read_event_config_new)(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir);
|
||||
|
||||
int (*write_event_config_new)(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan,
|
||||
enum iio_event_type type,
|
||||
enum iio_event_direction dir,
|
||||
int state);
|
||||
|
||||
int (*read_event_value_new)(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);
|
||||
|
||||
int (*write_event_value_new)(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);
|
||||
|
||||
int (*validate_trigger)(struct iio_dev *indio_dev,
|
||||
struct iio_trigger *trig);
|
||||
int (*update_scan_mode)(struct iio_dev *indio_dev,
|
||||
|
|
|
@ -54,6 +54,26 @@ enum iio_modifier {
|
|||
IIO_MOD_LIGHT_BLUE,
|
||||
};
|
||||
|
||||
enum iio_event_type {
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_TYPE_MAG,
|
||||
IIO_EV_TYPE_ROC,
|
||||
IIO_EV_TYPE_THRESH_ADAPTIVE,
|
||||
IIO_EV_TYPE_MAG_ADAPTIVE,
|
||||
};
|
||||
|
||||
enum iio_event_info {
|
||||
IIO_EV_INFO_ENABLE,
|
||||
IIO_EV_INFO_VALUE,
|
||||
IIO_EV_INFO_HYSTERESIS,
|
||||
};
|
||||
|
||||
enum iio_event_direction {
|
||||
IIO_EV_DIR_EITHER,
|
||||
IIO_EV_DIR_RISING,
|
||||
IIO_EV_DIR_FALLING,
|
||||
};
|
||||
|
||||
#define IIO_VAL_INT 1
|
||||
#define IIO_VAL_INT_PLUS_MICRO 2
|
||||
#define IIO_VAL_INT_PLUS_NANO 3
|
||||
|
|
Loading…
Reference in a new issue