diff options
57 files changed, 2905 insertions, 1238 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 2d73620874b..b20e829d350 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -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 diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt index 723c205cb10..d1061469f63 100644 --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt @@ -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: diff --git a/Documentation/devicetree/bindings/iio/light/cm36651.txt b/Documentation/devicetree/bindings/iio/light/cm36651.txt new file mode 100644 index 00000000000..c03e19db455 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/cm36651.txt @@ -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>; + }; + + /* ... */ + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 2956800f024..04eab45dd14 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -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. diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h index 048a57f76bd..c287307b9a3 100644 --- a/arch/arm/mach-at91/include/mach/at91_adc.h +++ b/arch/arm/mach-at91/include/mach/at91_adc.h @@ -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 diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c index d9b350756f9..a1e642ee13d 100644 --- a/drivers/iio/accel/st_accel_buffer.c +++ b/drivers/iio/accel/st_accel_buffer.c @@ -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) diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index f5723cbd203..58e945594c7 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -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) diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index faedd0e165f..acb7f90359a 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -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) { diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 2b591127476..e6fbd3e7098 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -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, diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 8b93295369b..17df74908db 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -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 @@ ret: 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,15 +997,9 @@ 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 * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock @@ -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), }, }; diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 2b34d2f02cf..cc07b3765fe 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -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 @@ error_ret: } 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, diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index bc93f538cb1..12948325431 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -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> diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index bdf03468f3b..adff9cbbcbc 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -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> diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index ee5f72bffe5..b3a82b4d1a7 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -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> diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 8fb5429e39a..ef54d8a588d 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -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) diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c index 841fec1e78b..2d9c6f8c06d 100644 --- a/drivers/iio/buffer_cb.c +++ b/drivers/iio/buffer_cb.c @@ -12,17 +12,27 @@ struct iio_cb_buffer { struct iio_channel *channels; }; -static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data) +static struct iio_cb_buffer *buffer_to_cb_buffer(struct iio_buffer *buffer) { - struct iio_cb_buffer *cb_buff = container_of(buffer, - struct iio_cb_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 = 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); diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 567c4bd546e..c44afeb06f5 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -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, }; diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c index 69017c7ec30..d67b17b6a7a 100644 --- a/drivers/iio/gyro/st_gyro_buffer.c +++ b/drivers/iio/gyro/st_gyro_buffer.c @@ -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) diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index 9209f47b273..f6db6af36ba 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -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 diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index e9f389b9da6..d7ab258e3a4 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -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 @@ error_ret: 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 @@ error_run_postdisable: 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 @@ done: } 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 @@ error_clear_mux_table: 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); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index ecf58963ac2..f7211576abe 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -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 @@ error_clear_attrs: 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); diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 36f0c8e0eb3..dac15b9f9df 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -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; - - ret = indio_dev->info->read_event_value(indio_dev, - this_attr->address, &val); - if (ret < 0) - return ret; + int val, val2; + int 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 @@ error_ret: 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); } diff --git a/drivers/iio/industrialio-triggered-buffer.c b/drivers/iio/industrialio-triggered-buffer.c index 46c619b0d8c..d6f54930b34 100644 --- a/drivers/iio/industrialio-triggered-buffer.c +++ b/drivers/iio/industrialio-triggered-buffer.c @@ -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, diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c index 538d4616e48..95c6fc81c2c 100644 --- a/drivers/iio/kfifo_buf.c +++ b/drivers/iio/kfifo_buf.c @@ -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); diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 0a25ae6b132..f98c2b50925 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -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 diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index cef590f2ff0..daa327f39e0 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -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 diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 66a58bda6dc..51097bbd59c 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -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, diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c new file mode 100644 index 00000000000..21df5713001 --- /dev/null +++ b/drivers/iio/light/cm36651.c @@ -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"); diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index b1e4615b87e..dc79835be30 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -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 @@ done: 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 @@ error_unlock: } 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 @@ error_unlock: } 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 @@ error_unlock: 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 @@ error_unlock: } static const struct iio_buffer_setup_ops gp2ap020a00f_buffer_setup_ops = { - .preenable = &iio_sw_buffer_preenable, .postenable = &gp2ap020a00f_buffer_postenable, .predisable = &gp2ap020a00f_buffer_predisable, }; diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index ebb962c5c32..5e5d9dea22c 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -526,6 +526,20 @@ error_ret: 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 @@ out: } 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, diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c index 708857bdb47..bf427dc0d22 100644 --- a/drivers/iio/magnetometer/st_magn_buffer.c +++ b/drivers/iio/magnetometer/st_magn_buffer.c @@ -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) diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c index f877ef8af52..b37b1c9ac93 100644 --- a/drivers/iio/pressure/st_pressure_buffer.c +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -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) diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h index cf32ae099cd..35154d60faf 100644 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ b/drivers/staging/iio/Documentation/iio_utils.h @@ -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); diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index bb852dc9c98..2789be381f1 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -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 @@ error_ret: } 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, }; diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index ed7de471e3f..79cefe0a516 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -382,7 +382,6 @@ error_ret: } 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; diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index 6a9ca20ea22..c49e6ef9d05 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -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 @@ done: * 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 @@ error_ret: * 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, }; diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index db44240186e..ea0af6d81d2 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -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 diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index cabc7a367db..1cf476484d7 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -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. diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c index ccaa8d6f8bc..d13f8aeeb62 100644 --- a/drivers/staging/iio/adc/ad7291.c +++ b/drivers/staging/iio/adc/ad7291.c @@ -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, }; diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h index b51680c1c33..a591aa6feae 100644 --- a/drivers/staging/iio/adc/ad799x.h +++ b/drivers/staging/iio/adc/ad799x.h @@ -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 diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c index eb6a690e6e9..9428be82b65 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -252,98 +252,70 @@ error_ret_mutex: } 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 @@ done: 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, - &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, +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 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, diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c index ce7ff3e6cd2..ef0a21d8ce1 100644 --- a/drivers/staging/iio/adc/lpc32xx_adc.c +++ b/drivers/staging/iio/adc/lpc32xx_adc.c @@ -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; } diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index dfd1bc1cc56..1bb03e196aa 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -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; diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c index 657e01bd733..970d9edc73b 100644 --- a/drivers/staging/iio/adc/spear_adc.c +++ b/drivers/staging/iio/adc/spear_adc.c @@ -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; diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index 618d820eb52..7e7f9890a64 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -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 @@ error_ret: } 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, }; /* diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c index 9135e603f58..1fac9894b18 100644 --- a/drivers/staging/iio/iio_simple_dummy.c +++ b/drivers/staging/iio/iio_simple_dummy.c @@ -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 */ }; diff --git a/drivers/staging/iio/iio_simple_dummy.h b/drivers/staging/iio/iio_simple_dummy.h index c9e8702caca..b126196cdf3 100644 --- a/drivers/staging/iio/iio_simple_dummy.h +++ b/drivers/staging/iio/iio_simple_dummy.h @@ -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); diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c index 09c93ac7351..46c134b2a5d 100644 --- a/drivers/staging/iio/iio_simple_dummy_buffer.c +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c @@ -99,14 +99,6 @@ done: 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. * Replace this to mess with hardware state before we attach the @@ -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; diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c index 317b77465db..812ebd05a7f 100644 --- a/drivers/staging/iio/iio_simple_dummy_events.c +++ b/drivers/staging/iio/iio_simple_dummy_events.c @@ -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); diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 712f3c22ce6..0a4298b744e 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -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; diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index 9c43dcf444c..18805029d2a 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -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, diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c index b29622c6f15..99421f90d18 100644 --- a/drivers/staging/iio/magnetometer/hmc5843.c +++ b/drivers/staging/iio/magnetometer/hmc5843.c @@ -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,76 +67,28 @@ 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 * | Data output rate (Hz) | Data output rate (Hz) @@ -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,85 +161,34 @@ 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); - mutex_unlock(&data->lock); - if (result < 0) - return -EINVAL; - - *val = sign_extend32(result, 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); + return 0; } -static ssize_t hmc5843_set_operating_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) +/* Return the measurement value from the specified channel */ +static int hmc5843_read_measurement(struct hmc5843_data *data, + int idx, int *val) { - 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; + s32 result; + __be16 values[3]; 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; + result = hmc5843_wait_measurement(data); + if (result < 0) { + mutex_unlock(&data->lock); + return result; } - data->operating_mode = operating_mode; - -exit: + result = i2c_smbus_read_i2c_block_data(data->client, + HMC5843_DATA_OUT_MSB_REGS, sizeof(values), (u8 *) values); mutex_unlock(&data->lock); - return count; -} + if (result < 0) + return -EINVAL; -static IIO_DEVICE_ATTR(operating_mode, - S_IWUSR | S_IRUGO, - hmc5843_show_operating_mode, - hmc5843_set_operating_mode, - HMC5843_MODE_REG); + *val = sign_extend32(be16_to_cpu(values[idx]), 15); + return IIO_VAL_INT; +} /* * API for setting the measurement configuration to @@ -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, - struct device_attribute *attr, char *buf) +static int hmc5843_set_range_gain(struct hmc5843_data *data, u8 range) { - struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); + int ret; - return hmc5843_show_int_plus_micros(buf, - data->variant->regval_to_samp_freq, HMC5843_RATE_NOT_USED); -} + 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); -static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_samp_freq_avail); + return ret; +} -static s32 hmc5843_set_rate(struct hmc5843_data *data, u8 rate) +static ssize_t hmc5843_show_scale_avail(struct device *dev, + struct device_attribute *attr, char *buf) { - u8 reg_val = data->meas_conf | (rate << HMC5843_RATE_OFFSET); + struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); - return i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A, - reg_val); -} + size_t len = 0; + int i; -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); -} + for (i = 0; i < HMC5843_RANGE_GAINS; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, + "0.%09d ", data->variant->regval_to_nanoscale[i]); -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); + /* replace trailing space by newline */ + buf[len - 1] = '\n'; - range = data->range; - return sprintf(buf, "%d\n", data->variant->regval_to_input_field_mga[range]); + return len; } -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; +static IIO_DEVICE_ATTR(scale_available, S_IRUGO, + hmc5843_show_scale_avail, NULL, 0); - mutex_lock(&data->lock); - error = kstrtoul(buf, 10, &range); - if (error) { - count = error; - goto exit; - } - dev_dbg(dev, "set range to %lu\n", range); +static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2) +{ + int i; - if (range > HMC5843_RANGE_GAIN_MAX) { - count = -EINVAL; - goto exit; - } + if (val != 0) + return -EINVAL; - data->range = range; - range = range << HMC5843_RANGE_GAIN_OFFSET; - if (i2c_smbus_write_byte_data(data->client, this_attr->address, range)) - count = -EINVAL; + for (i = 0; i < HMC5843_RANGE_GAINS; i++) + if (val2 == data->variant->regval_to_nanoscale[i]) + return i; -exit: - mutex_unlock(&data->lock); - return count; + return -EINVAL; } -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; + } +} + +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; } } -#define HMC5843_CHANNEL(axis, addr) \ +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; + + ret = hmc5843_init(data); + if (ret < 0) + return ret; - hmc5843_init(data); + ret = iio_triggered_buffer_setup(indio_dev, NULL, + hmc5843_trigger_handler, NULL); + if (ret < 0) + return ret; - err = iio_device_register(indio_dev); - if (err) - return err; + 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); diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c index 4080995c99b..c0accf8cce9 100644 --- a/drivers/staging/iio/meter/ade7758_ring.c +++ b/drivers/staging/iio/meter/ade7758_ring.c @@ -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, diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index a1124bdc4ca..15607b45221 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -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_ */ diff --git a/include/linux/iio/events.h b/include/linux/iio/events.h index 13ce220c700..5dab2c41031 100644 --- a/include/linux/iio/events.h +++ b/include/linux/iio/events.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. diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index ac1cb8f1858..256a90a1bea 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -139,6 +139,29 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, } /** + * 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. * @channel: What number do we wish to assign the channel. @@ -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, diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 88bf0f0d27b..4ac928ee31c 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -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 |