xref: /linux/drivers/iio/adc/rohm-bd79124.c (revision 0227b49b50276657243e54f5609e65c4f0eaaf4d)
13f57a3b9SMatti Vaittinen // SPDX-License-Identifier: GPL-2.0-only
23f57a3b9SMatti Vaittinen /*
33f57a3b9SMatti Vaittinen  * ROHM ADC driver for BD79124 ADC/GPO device
43f57a3b9SMatti Vaittinen  * https://fscdn.rohm.com/en/products/databook/datasheet/ic/data_converter/dac/bd79124muf-c-e.pdf
53f57a3b9SMatti Vaittinen  *
63f57a3b9SMatti Vaittinen  * Copyright (c) 2025, ROHM Semiconductor.
73f57a3b9SMatti Vaittinen  */
83f57a3b9SMatti Vaittinen 
93f57a3b9SMatti Vaittinen #include <linux/array_size.h>
103f57a3b9SMatti Vaittinen #include <linux/bitfield.h>
113f57a3b9SMatti Vaittinen #include <linux/bitmap.h>
123f57a3b9SMatti Vaittinen #include <linux/bits.h>
133f57a3b9SMatti Vaittinen #include <linux/device.h>
143f57a3b9SMatti Vaittinen #include <linux/delay.h>
153f57a3b9SMatti Vaittinen #include <linux/devm-helpers.h>
163f57a3b9SMatti Vaittinen #include <linux/err.h>
173f57a3b9SMatti Vaittinen #include <linux/gpio/driver.h>
183f57a3b9SMatti Vaittinen #include <linux/i2c.h>
193f57a3b9SMatti Vaittinen #include <linux/interrupt.h>
203f57a3b9SMatti Vaittinen #include <linux/irqreturn.h>
213f57a3b9SMatti Vaittinen #include <linux/module.h>
223f57a3b9SMatti Vaittinen #include <linux/mod_devicetable.h>
233f57a3b9SMatti Vaittinen #include <linux/regmap.h>
243f57a3b9SMatti Vaittinen #include <linux/types.h>
253f57a3b9SMatti Vaittinen 
263f57a3b9SMatti Vaittinen #include <asm/byteorder.h>
273f57a3b9SMatti Vaittinen 
283f57a3b9SMatti Vaittinen #include <linux/iio/events.h>
293f57a3b9SMatti Vaittinen #include <linux/iio/iio.h>
303f57a3b9SMatti Vaittinen #include <linux/iio/adc-helpers.h>
313f57a3b9SMatti Vaittinen 
323f57a3b9SMatti Vaittinen #define BD79124_I2C_MULTI_READ		0x30
333f57a3b9SMatti Vaittinen #define BD79124_I2C_MULTI_WRITE		0x28
343f57a3b9SMatti Vaittinen #define BD79124_REG_MAX			0xaf
353f57a3b9SMatti Vaittinen 
363f57a3b9SMatti Vaittinen #define BD79124_REG_SYSTEM_STATUS	0x00
373f57a3b9SMatti Vaittinen #define BD79124_REG_GEN_CFG		0x01
383f57a3b9SMatti Vaittinen #define BD79124_REG_OPMODE_CFG		0x04
393f57a3b9SMatti Vaittinen #define BD79124_REG_PINCFG		0x05
403f57a3b9SMatti Vaittinen #define BD79124_REG_GPO_VAL		0x0B
413f57a3b9SMatti Vaittinen #define BD79124_REG_SEQ_CFG		0x10
423f57a3b9SMatti Vaittinen #define BD79124_REG_MANUAL_CHANNELS	0x11
433f57a3b9SMatti Vaittinen #define BD79124_REG_AUTO_CHANNELS	0x12
443f57a3b9SMatti Vaittinen #define BD79124_REG_ALERT_CH_SEL	0x14
453f57a3b9SMatti Vaittinen #define BD79124_REG_EVENT_FLAG		0x18
463f57a3b9SMatti Vaittinen #define BD79124_REG_EVENT_FLAG_HI	0x1a
473f57a3b9SMatti Vaittinen #define BD79124_REG_EVENT_FLAG_LO	0x1c
483f57a3b9SMatti Vaittinen #define BD79124_REG_HYSTERESIS_CH0	0x20
493f57a3b9SMatti Vaittinen #define BD79124_REG_EVENTCOUNT_CH0	0x22
503f57a3b9SMatti Vaittinen #define BD79124_REG_RECENT_CH0_LSB	0xa0
513f57a3b9SMatti Vaittinen #define BD79124_REG_RECENT_CH7_MSB	0xaf
523f57a3b9SMatti Vaittinen 
533f57a3b9SMatti Vaittinen #define BD79124_ADC_BITS 12
543f57a3b9SMatti Vaittinen 
553f57a3b9SMatti Vaittinen /* Masks for the BD79124_REG_OPMODE_CFG */
563f57a3b9SMatti Vaittinen #define BD79124_MSK_CONV_MODE GENMASK(6, 5)
573f57a3b9SMatti Vaittinen #define BD79124_CONV_MODE_MANSEQ 0
583f57a3b9SMatti Vaittinen #define BD79124_CONV_MODE_AUTO 1
593f57a3b9SMatti Vaittinen #define BD79124_MSK_AUTO_INTERVAL GENMASK(1, 0)
603f57a3b9SMatti Vaittinen #define BD79124_INTERVAL_750_US 0
613f57a3b9SMatti Vaittinen 
623f57a3b9SMatti Vaittinen /* Masks for the BD79124_REG_GEN_CFG */
633f57a3b9SMatti Vaittinen #define BD79124_MSK_DWC_EN BIT(4)
643f57a3b9SMatti Vaittinen #define BD79124_MSK_STATS_EN BIT(5)
653f57a3b9SMatti Vaittinen 
663f57a3b9SMatti Vaittinen /* Masks for the BD79124_REG_SEQ_CFG */
673f57a3b9SMatti Vaittinen #define BD79124_MSK_SEQ_START BIT(4)
683f57a3b9SMatti Vaittinen #define BD79124_MSK_SEQ_MODE GENMASK(1, 0)
693f57a3b9SMatti Vaittinen #define BD79124_MSK_SEQ_MANUAL 0
703f57a3b9SMatti Vaittinen #define BD79124_MSK_SEQ_SEQ 1
713f57a3b9SMatti Vaittinen 
723f57a3b9SMatti Vaittinen #define BD79124_MSK_HYSTERESIS GENMASK(3, 0)
733f57a3b9SMatti Vaittinen #define BD79124_LOW_LIMIT_MIN 0
743f57a3b9SMatti Vaittinen #define BD79124_HIGH_LIMIT_MAX GENMASK(11, 0)
753f57a3b9SMatti Vaittinen 
763f57a3b9SMatti Vaittinen /*
773f57a3b9SMatti Vaittinen  * The high limit, low limit and last measurement result are each stored in
783f57a3b9SMatti Vaittinen  * 2 consequtive registers. 4 bits are in the high bits of the first register
793f57a3b9SMatti Vaittinen  * and 8 bits in the next register.
803f57a3b9SMatti Vaittinen  *
813f57a3b9SMatti Vaittinen  * These macros return the address of the first reg for the given channel.
823f57a3b9SMatti Vaittinen  */
833f57a3b9SMatti Vaittinen #define BD79124_GET_HIGH_LIMIT_REG(ch) (BD79124_REG_HYSTERESIS_CH0 + (ch) * 4)
843f57a3b9SMatti Vaittinen #define BD79124_GET_LOW_LIMIT_REG(ch) (BD79124_REG_EVENTCOUNT_CH0 + (ch) * 4)
853f57a3b9SMatti Vaittinen #define BD79124_GET_LIMIT_REG(ch, dir) ((dir) == IIO_EV_DIR_RISING ?		\
863f57a3b9SMatti Vaittinen 		BD79124_GET_HIGH_LIMIT_REG(ch) : BD79124_GET_LOW_LIMIT_REG(ch))
873f57a3b9SMatti Vaittinen #define BD79124_GET_RECENT_RES_REG(ch) (BD79124_REG_RECENT_CH0_LSB + (ch) * 2)
883f57a3b9SMatti Vaittinen 
893f57a3b9SMatti Vaittinen /*
903f57a3b9SMatti Vaittinen  * The hysteresis for a channel is stored in the same register where the
913f57a3b9SMatti Vaittinen  * 4 bits of high limit reside.
923f57a3b9SMatti Vaittinen  */
933f57a3b9SMatti Vaittinen #define BD79124_GET_HYSTERESIS_REG(ch) BD79124_GET_HIGH_LIMIT_REG(ch)
943f57a3b9SMatti Vaittinen 
953f57a3b9SMatti Vaittinen #define BD79124_MAX_NUM_CHANNELS 8
963f57a3b9SMatti Vaittinen 
973f57a3b9SMatti Vaittinen struct bd79124_data {
983f57a3b9SMatti Vaittinen 	s64 timestamp;
993f57a3b9SMatti Vaittinen 	struct regmap *map;
1003f57a3b9SMatti Vaittinen 	struct device *dev;
1013f57a3b9SMatti Vaittinen 	int vmax;
1023f57a3b9SMatti Vaittinen 	/*
1033f57a3b9SMatti Vaittinen 	 * Keep measurement status so read_raw() knows if the measurement needs
1043f57a3b9SMatti Vaittinen 	 * to be started.
1053f57a3b9SMatti Vaittinen 	 */
1063f57a3b9SMatti Vaittinen 	int alarm_monitored[BD79124_MAX_NUM_CHANNELS];
1073f57a3b9SMatti Vaittinen 	/*
1083f57a3b9SMatti Vaittinen 	 * The BD79124 does not allow disabling/enabling limit separately for
1093f57a3b9SMatti Vaittinen 	 * one direction only. Hence, we do the disabling by changing the limit
1103f57a3b9SMatti Vaittinen 	 * to maximum/minimum measurable value. This means we need to cache
1113f57a3b9SMatti Vaittinen 	 * the limit in order to maintain it over the time limit is disabled.
1123f57a3b9SMatti Vaittinen 	 */
1133f57a3b9SMatti Vaittinen 	u16 alarm_r_limit[BD79124_MAX_NUM_CHANNELS];
1143f57a3b9SMatti Vaittinen 	u16 alarm_f_limit[BD79124_MAX_NUM_CHANNELS];
1153f57a3b9SMatti Vaittinen 	/* Bitmask of disabled events (for rate limiting) for each channel. */
1163f57a3b9SMatti Vaittinen 	int alarm_suppressed[BD79124_MAX_NUM_CHANNELS];
1173f57a3b9SMatti Vaittinen 	/*
1183f57a3b9SMatti Vaittinen 	 * The BD79124 is configured to run the measurements in the background.
1193f57a3b9SMatti Vaittinen 	 * This is done for the event monitoring as well as for the read_raw().
1203f57a3b9SMatti Vaittinen 	 * Protect the measurement starting/stopping using a mutex.
1213f57a3b9SMatti Vaittinen 	 */
1223f57a3b9SMatti Vaittinen 	struct mutex mutex;
1233f57a3b9SMatti Vaittinen 	struct delayed_work alm_enable_work;
1243f57a3b9SMatti Vaittinen 	struct gpio_chip gc;
1253f57a3b9SMatti Vaittinen 	u8 gpio_valid_mask;
1263f57a3b9SMatti Vaittinen };
1273f57a3b9SMatti Vaittinen 
1283f57a3b9SMatti Vaittinen static const struct regmap_range bd79124_ro_ranges[] = {
1293f57a3b9SMatti Vaittinen 	{
1303f57a3b9SMatti Vaittinen 		.range_min = BD79124_REG_EVENT_FLAG,
1313f57a3b9SMatti Vaittinen 		.range_max = BD79124_REG_EVENT_FLAG,
1323f57a3b9SMatti Vaittinen 	}, {
1333f57a3b9SMatti Vaittinen 		.range_min = BD79124_REG_RECENT_CH0_LSB,
1343f57a3b9SMatti Vaittinen 		.range_max = BD79124_REG_RECENT_CH7_MSB,
1353f57a3b9SMatti Vaittinen 	},
1363f57a3b9SMatti Vaittinen };
1373f57a3b9SMatti Vaittinen 
1383f57a3b9SMatti Vaittinen static const struct regmap_access_table bd79124_ro_regs = {
1393f57a3b9SMatti Vaittinen 	.no_ranges	= &bd79124_ro_ranges[0],
1403f57a3b9SMatti Vaittinen 	.n_no_ranges	= ARRAY_SIZE(bd79124_ro_ranges),
1413f57a3b9SMatti Vaittinen };
1423f57a3b9SMatti Vaittinen 
1433f57a3b9SMatti Vaittinen static const struct regmap_range bd79124_volatile_ranges[] = {
1443f57a3b9SMatti Vaittinen 	{
1453f57a3b9SMatti Vaittinen 		.range_min = BD79124_REG_RECENT_CH0_LSB,
1463f57a3b9SMatti Vaittinen 		.range_max = BD79124_REG_RECENT_CH7_MSB,
1473f57a3b9SMatti Vaittinen 	}, {
1483f57a3b9SMatti Vaittinen 		.range_min = BD79124_REG_EVENT_FLAG,
1493f57a3b9SMatti Vaittinen 		.range_max = BD79124_REG_EVENT_FLAG,
1503f57a3b9SMatti Vaittinen 	}, {
1513f57a3b9SMatti Vaittinen 		.range_min = BD79124_REG_EVENT_FLAG_HI,
1523f57a3b9SMatti Vaittinen 		.range_max = BD79124_REG_EVENT_FLAG_HI,
1533f57a3b9SMatti Vaittinen 	}, {
1543f57a3b9SMatti Vaittinen 		.range_min = BD79124_REG_EVENT_FLAG_LO,
1553f57a3b9SMatti Vaittinen 		.range_max = BD79124_REG_EVENT_FLAG_LO,
1563f57a3b9SMatti Vaittinen 	}, {
1573f57a3b9SMatti Vaittinen 		.range_min = BD79124_REG_SYSTEM_STATUS,
1583f57a3b9SMatti Vaittinen 		.range_max = BD79124_REG_SYSTEM_STATUS,
1593f57a3b9SMatti Vaittinen 	},
1603f57a3b9SMatti Vaittinen };
1613f57a3b9SMatti Vaittinen 
1623f57a3b9SMatti Vaittinen static const struct regmap_access_table bd79124_volatile_regs = {
1633f57a3b9SMatti Vaittinen 	.yes_ranges	= &bd79124_volatile_ranges[0],
1643f57a3b9SMatti Vaittinen 	.n_yes_ranges	= ARRAY_SIZE(bd79124_volatile_ranges),
1653f57a3b9SMatti Vaittinen };
1663f57a3b9SMatti Vaittinen 
1673f57a3b9SMatti Vaittinen static const struct regmap_range bd79124_precious_ranges[] = {
1683f57a3b9SMatti Vaittinen 	{
1693f57a3b9SMatti Vaittinen 		.range_min = BD79124_REG_EVENT_FLAG_HI,
1703f57a3b9SMatti Vaittinen 		.range_max = BD79124_REG_EVENT_FLAG_HI,
1713f57a3b9SMatti Vaittinen 	}, {
1723f57a3b9SMatti Vaittinen 		.range_min = BD79124_REG_EVENT_FLAG_LO,
1733f57a3b9SMatti Vaittinen 		.range_max = BD79124_REG_EVENT_FLAG_LO,
1743f57a3b9SMatti Vaittinen 	},
1753f57a3b9SMatti Vaittinen };
1763f57a3b9SMatti Vaittinen 
1773f57a3b9SMatti Vaittinen static const struct regmap_access_table bd79124_precious_regs = {
1783f57a3b9SMatti Vaittinen 	.yes_ranges	= &bd79124_precious_ranges[0],
1793f57a3b9SMatti Vaittinen 	.n_yes_ranges	= ARRAY_SIZE(bd79124_precious_ranges),
1803f57a3b9SMatti Vaittinen };
1813f57a3b9SMatti Vaittinen 
1823f57a3b9SMatti Vaittinen static const struct regmap_config bd79124_regmap = {
1833f57a3b9SMatti Vaittinen 	.reg_bits		= 16,
1843f57a3b9SMatti Vaittinen 	.val_bits		= 8,
1853f57a3b9SMatti Vaittinen 	.read_flag_mask		= BD79124_I2C_MULTI_READ,
1863f57a3b9SMatti Vaittinen 	.write_flag_mask	= BD79124_I2C_MULTI_WRITE,
1873f57a3b9SMatti Vaittinen 	.max_register		= BD79124_REG_MAX,
1883f57a3b9SMatti Vaittinen 	.cache_type		= REGCACHE_MAPLE,
1893f57a3b9SMatti Vaittinen 	.volatile_table		= &bd79124_volatile_regs,
1903f57a3b9SMatti Vaittinen 	.wr_table		= &bd79124_ro_regs,
1913f57a3b9SMatti Vaittinen 	.precious_table		= &bd79124_precious_regs,
1923f57a3b9SMatti Vaittinen };
1933f57a3b9SMatti Vaittinen 
bd79124gpo_direction_get(struct gpio_chip * gc,unsigned int offset)1943f57a3b9SMatti Vaittinen static int bd79124gpo_direction_get(struct gpio_chip *gc, unsigned int offset)
1953f57a3b9SMatti Vaittinen {
1963f57a3b9SMatti Vaittinen 	return GPIO_LINE_DIRECTION_OUT;
1973f57a3b9SMatti Vaittinen }
1983f57a3b9SMatti Vaittinen 
bd79124gpo_set(struct gpio_chip * gc,unsigned int offset,int value)199a34b88b4SMatti Vaittinen static int bd79124gpo_set(struct gpio_chip *gc, unsigned int offset, int value)
2003f57a3b9SMatti Vaittinen {
2013f57a3b9SMatti Vaittinen 	struct bd79124_data *data = gpiochip_get_data(gc);
2023f57a3b9SMatti Vaittinen 
203a34b88b4SMatti Vaittinen 	return regmap_assign_bits(data->map, BD79124_REG_GPO_VAL, BIT(offset),
204a34b88b4SMatti Vaittinen 				  value);
2053f57a3b9SMatti Vaittinen }
2063f57a3b9SMatti Vaittinen 
bd79124gpo_set_multiple(struct gpio_chip * gc,unsigned long * mask,unsigned long * bits)207a34b88b4SMatti Vaittinen static int bd79124gpo_set_multiple(struct gpio_chip *gc, unsigned long *mask,
2083f57a3b9SMatti Vaittinen 				    unsigned long *bits)
2093f57a3b9SMatti Vaittinen {
210a34b88b4SMatti Vaittinen 	unsigned int all_gpos;
2113f57a3b9SMatti Vaittinen 	int ret;
2123f57a3b9SMatti Vaittinen 	struct bd79124_data *data = gpiochip_get_data(gc);
2133f57a3b9SMatti Vaittinen 
2143f57a3b9SMatti Vaittinen 	/*
2153f57a3b9SMatti Vaittinen 	 * Ensure all GPIOs in 'mask' are set to be GPIOs
2163f57a3b9SMatti Vaittinen 	 * The valid_mask was not obeyed by the gpiolib in all cases prior the
2173f57a3b9SMatti Vaittinen 	 * https://lore.kernel.org/all/cd5e067b80e1bb590027bc3bfa817e7f794f21c3.1741180097.git.mazziesaccount@gmail.com/
2183f57a3b9SMatti Vaittinen 	 *
2193f57a3b9SMatti Vaittinen 	 * Keep this check here for a couple of cycles.
2203f57a3b9SMatti Vaittinen 	 */
2213f57a3b9SMatti Vaittinen 	ret = regmap_read(data->map, BD79124_REG_PINCFG, &all_gpos);
2223f57a3b9SMatti Vaittinen 	if (ret)
223a34b88b4SMatti Vaittinen 		return ret;
2243f57a3b9SMatti Vaittinen 
2253f57a3b9SMatti Vaittinen 	if (all_gpos ^ *mask) {
2263f57a3b9SMatti Vaittinen 		dev_dbg(data->dev, "Invalid mux config. Can't set value.\n");
227a34b88b4SMatti Vaittinen 
228a34b88b4SMatti Vaittinen 		return -EINVAL;
2293f57a3b9SMatti Vaittinen 	}
2303f57a3b9SMatti Vaittinen 
231a34b88b4SMatti Vaittinen 	return regmap_update_bits(data->map, BD79124_REG_GPO_VAL, *mask, *bits);
2323f57a3b9SMatti Vaittinen }
2333f57a3b9SMatti Vaittinen 
bd79124_init_valid_mask(struct gpio_chip * gc,unsigned long * valid_mask,unsigned int ngpios)2343f57a3b9SMatti Vaittinen static int bd79124_init_valid_mask(struct gpio_chip *gc,
2353f57a3b9SMatti Vaittinen 				   unsigned long *valid_mask,
2363f57a3b9SMatti Vaittinen 				   unsigned int ngpios)
2373f57a3b9SMatti Vaittinen {
2383f57a3b9SMatti Vaittinen 	struct bd79124_data *data = gpiochip_get_data(gc);
2393f57a3b9SMatti Vaittinen 
2403f57a3b9SMatti Vaittinen 	*valid_mask = data->gpio_valid_mask;
2413f57a3b9SMatti Vaittinen 
2423f57a3b9SMatti Vaittinen 	return 0;
2433f57a3b9SMatti Vaittinen }
2443f57a3b9SMatti Vaittinen 
2453f57a3b9SMatti Vaittinen /* Template for GPIO chip */
2463f57a3b9SMatti Vaittinen static const struct gpio_chip bd79124gpo_chip = {
2473f57a3b9SMatti Vaittinen 	.label			= "bd79124-gpo",
2483f57a3b9SMatti Vaittinen 	.get_direction		= bd79124gpo_direction_get,
249*d9d87d90SBartosz Golaszewski 	.set			= bd79124gpo_set,
250*d9d87d90SBartosz Golaszewski 	.set_multiple		= bd79124gpo_set_multiple,
2513f57a3b9SMatti Vaittinen 	.init_valid_mask	= bd79124_init_valid_mask,
2523f57a3b9SMatti Vaittinen 	.can_sleep		= true,
2533f57a3b9SMatti Vaittinen 	.ngpio			= 8,
2543f57a3b9SMatti Vaittinen 	.base			= -1,
2553f57a3b9SMatti Vaittinen };
2563f57a3b9SMatti Vaittinen 
2573f57a3b9SMatti Vaittinen struct bd79124_raw {
2583f57a3b9SMatti Vaittinen 	u8 val_bit3_0; /* Is set in high bits of the byte */
2593f57a3b9SMatti Vaittinen 	u8 val_bit11_4;
2603f57a3b9SMatti Vaittinen };
2613f57a3b9SMatti Vaittinen #define BD79124_RAW_TO_INT(r) ((r.val_bit11_4 << 4) | (r.val_bit3_0 >> 4))
2623f57a3b9SMatti Vaittinen #define BD79124_INT_TO_RAW(val) {					\
2633f57a3b9SMatti Vaittinen 	.val_bit11_4 = (val) >> 4,					\
2643f57a3b9SMatti Vaittinen 	.val_bit3_0 = (val) << 4,					\
2653f57a3b9SMatti Vaittinen }
2663f57a3b9SMatti Vaittinen 
2673f57a3b9SMatti Vaittinen /*
2683f57a3b9SMatti Vaittinen  * The high and low limits as well as the recent result values are stored in
2693f57a3b9SMatti Vaittinen  * the same way in 2 consequent registers. The first register contains 4 bits
2703f57a3b9SMatti Vaittinen  * of the value. These bits are stored in the high bits [7:4] of register, but
2713f57a3b9SMatti Vaittinen  * they represent the low bits [3:0] of the value.
2723f57a3b9SMatti Vaittinen  * The value bits [11:4] are stored in the next register.
2733f57a3b9SMatti Vaittinen  *
2743f57a3b9SMatti Vaittinen  * Read data from register and convert to integer.
2753f57a3b9SMatti Vaittinen  */
bd79124_read_reg_to_int(struct bd79124_data * data,int reg,unsigned int * val)2763f57a3b9SMatti Vaittinen static int bd79124_read_reg_to_int(struct bd79124_data *data, int reg,
2773f57a3b9SMatti Vaittinen 				   unsigned int *val)
2783f57a3b9SMatti Vaittinen {
2793f57a3b9SMatti Vaittinen 	int ret;
2803f57a3b9SMatti Vaittinen 	struct bd79124_raw raw;
2813f57a3b9SMatti Vaittinen 
2823f57a3b9SMatti Vaittinen 	ret = regmap_bulk_read(data->map, reg, &raw, sizeof(raw));
2833f57a3b9SMatti Vaittinen 	if (ret) {
2843f57a3b9SMatti Vaittinen 		dev_dbg(data->dev, "bulk_read failed %d\n", ret);
2853f57a3b9SMatti Vaittinen 
2863f57a3b9SMatti Vaittinen 		return ret;
2873f57a3b9SMatti Vaittinen 	}
2883f57a3b9SMatti Vaittinen 
2893f57a3b9SMatti Vaittinen 	*val = BD79124_RAW_TO_INT(raw);
2903f57a3b9SMatti Vaittinen 
2913f57a3b9SMatti Vaittinen 	return 0;
2923f57a3b9SMatti Vaittinen }
2933f57a3b9SMatti Vaittinen 
2943f57a3b9SMatti Vaittinen /*
2953f57a3b9SMatti Vaittinen  * The high and low limits as well as the recent result values are stored in
2963f57a3b9SMatti Vaittinen  * the same way in 2 consequent registers. The first register contains 4 bits
2973f57a3b9SMatti Vaittinen  * of the value. These bits are stored in the high bits [7:4] of register, but
2983f57a3b9SMatti Vaittinen  * they represent the low bits [3:0] of the value.
2993f57a3b9SMatti Vaittinen  * The value bits [11:4] are stored in the next register.
3003f57a3b9SMatti Vaittinen  *
3013f57a3b9SMatti Vaittinen  * Convert the integer to register format and write it using rmw cycle.
3023f57a3b9SMatti Vaittinen  */
bd79124_write_int_to_reg(struct bd79124_data * data,int reg,unsigned int val)3033f57a3b9SMatti Vaittinen static int bd79124_write_int_to_reg(struct bd79124_data *data, int reg,
3043f57a3b9SMatti Vaittinen 				    unsigned int val)
3053f57a3b9SMatti Vaittinen {
3063f57a3b9SMatti Vaittinen 	struct bd79124_raw raw = BD79124_INT_TO_RAW(val);
3073f57a3b9SMatti Vaittinen 	unsigned int tmp;
3083f57a3b9SMatti Vaittinen 	int ret;
3093f57a3b9SMatti Vaittinen 
3103f57a3b9SMatti Vaittinen 	ret = regmap_read(data->map, reg, &tmp);
3113f57a3b9SMatti Vaittinen 	if (ret)
3123f57a3b9SMatti Vaittinen 		return ret;
3133f57a3b9SMatti Vaittinen 
3143f57a3b9SMatti Vaittinen 	raw.val_bit3_0 |= (tmp & 0xf);
3153f57a3b9SMatti Vaittinen 
3163f57a3b9SMatti Vaittinen 	return regmap_bulk_write(data->map, reg, &raw, sizeof(raw));
3173f57a3b9SMatti Vaittinen }
3183f57a3b9SMatti Vaittinen 
3193f57a3b9SMatti Vaittinen static const struct iio_event_spec bd79124_events[] = {
3203f57a3b9SMatti Vaittinen 	{
3213f57a3b9SMatti Vaittinen 		.type = IIO_EV_TYPE_THRESH,
3223f57a3b9SMatti Vaittinen 		.dir = IIO_EV_DIR_RISING,
3233f57a3b9SMatti Vaittinen 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
3243f57a3b9SMatti Vaittinen 				 BIT(IIO_EV_INFO_ENABLE),
3253f57a3b9SMatti Vaittinen 	},
3263f57a3b9SMatti Vaittinen 	{
3273f57a3b9SMatti Vaittinen 		.type = IIO_EV_TYPE_THRESH,
3283f57a3b9SMatti Vaittinen 		.dir = IIO_EV_DIR_FALLING,
3293f57a3b9SMatti Vaittinen 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
3303f57a3b9SMatti Vaittinen 				 BIT(IIO_EV_INFO_ENABLE),
3313f57a3b9SMatti Vaittinen 	},
3323f57a3b9SMatti Vaittinen 	{
3333f57a3b9SMatti Vaittinen 		.type = IIO_EV_TYPE_THRESH,
3343f57a3b9SMatti Vaittinen 		.dir = IIO_EV_DIR_EITHER,
3353f57a3b9SMatti Vaittinen 		.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
3363f57a3b9SMatti Vaittinen 	},
3373f57a3b9SMatti Vaittinen };
3383f57a3b9SMatti Vaittinen 
3393f57a3b9SMatti Vaittinen static const struct iio_chan_spec bd79124_chan_template_noirq = {
3403f57a3b9SMatti Vaittinen 	.type = IIO_VOLTAGE,
3413f57a3b9SMatti Vaittinen 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
3423f57a3b9SMatti Vaittinen 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
3433f57a3b9SMatti Vaittinen 	.indexed = 1,
3443f57a3b9SMatti Vaittinen };
3453f57a3b9SMatti Vaittinen 
3463f57a3b9SMatti Vaittinen static const struct iio_chan_spec bd79124_chan_template = {
3473f57a3b9SMatti Vaittinen 	.type = IIO_VOLTAGE,
3483f57a3b9SMatti Vaittinen 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
3493f57a3b9SMatti Vaittinen 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
3503f57a3b9SMatti Vaittinen 	.indexed = 1,
3513f57a3b9SMatti Vaittinen 	.event_spec = bd79124_events,
3523f57a3b9SMatti Vaittinen 	.num_event_specs = ARRAY_SIZE(bd79124_events),
3533f57a3b9SMatti Vaittinen };
3543f57a3b9SMatti Vaittinen 
bd79124_read_event_value(struct iio_dev * iio_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)3553f57a3b9SMatti Vaittinen static int bd79124_read_event_value(struct iio_dev *iio_dev,
3563f57a3b9SMatti Vaittinen 				    const struct iio_chan_spec *chan,
3573f57a3b9SMatti Vaittinen 				    enum iio_event_type type,
3583f57a3b9SMatti Vaittinen 				    enum iio_event_direction dir,
3593f57a3b9SMatti Vaittinen 				    enum iio_event_info info, int *val,
3603f57a3b9SMatti Vaittinen 				    int *val2)
3613f57a3b9SMatti Vaittinen {
3623f57a3b9SMatti Vaittinen 	struct bd79124_data *data = iio_priv(iio_dev);
3633f57a3b9SMatti Vaittinen 	int ret, reg;
3643f57a3b9SMatti Vaittinen 
3653f57a3b9SMatti Vaittinen 	if (chan->channel >= BD79124_MAX_NUM_CHANNELS)
3663f57a3b9SMatti Vaittinen 		return -EINVAL;
3673f57a3b9SMatti Vaittinen 
3683f57a3b9SMatti Vaittinen 	switch (info) {
3693f57a3b9SMatti Vaittinen 	case IIO_EV_INFO_VALUE:
3703f57a3b9SMatti Vaittinen 		if (dir == IIO_EV_DIR_RISING)
3713f57a3b9SMatti Vaittinen 			*val = data->alarm_r_limit[chan->channel];
3723f57a3b9SMatti Vaittinen 		else if (dir == IIO_EV_DIR_FALLING)
3733f57a3b9SMatti Vaittinen 			*val = data->alarm_f_limit[chan->channel];
3743f57a3b9SMatti Vaittinen 		else
3753f57a3b9SMatti Vaittinen 			return -EINVAL;
3763f57a3b9SMatti Vaittinen 
3773f57a3b9SMatti Vaittinen 		return IIO_VAL_INT;
3783f57a3b9SMatti Vaittinen 
3793f57a3b9SMatti Vaittinen 	case IIO_EV_INFO_HYSTERESIS:
3803f57a3b9SMatti Vaittinen 		reg = BD79124_GET_HYSTERESIS_REG(chan->channel);
3813f57a3b9SMatti Vaittinen 		ret = regmap_read(data->map, reg, val);
3823f57a3b9SMatti Vaittinen 		if (ret)
3833f57a3b9SMatti Vaittinen 			return ret;
3843f57a3b9SMatti Vaittinen 
3853f57a3b9SMatti Vaittinen 		*val &= BD79124_MSK_HYSTERESIS;
3863f57a3b9SMatti Vaittinen 		/*
3873f57a3b9SMatti Vaittinen 		 * The data-sheet says the hysteresis register value needs to be
3883f57a3b9SMatti Vaittinen 		 * shifted left by 3.
3893f57a3b9SMatti Vaittinen 		 */
3903f57a3b9SMatti Vaittinen 		*val <<= 3;
3913f57a3b9SMatti Vaittinen 
3923f57a3b9SMatti Vaittinen 		return IIO_VAL_INT;
3933f57a3b9SMatti Vaittinen 
3943f57a3b9SMatti Vaittinen 	default:
3953f57a3b9SMatti Vaittinen 		return -EINVAL;
3963f57a3b9SMatti Vaittinen 	}
3973f57a3b9SMatti Vaittinen }
3983f57a3b9SMatti Vaittinen 
bd79124_start_measurement(struct bd79124_data * data,int chan)3993f57a3b9SMatti Vaittinen static int bd79124_start_measurement(struct bd79124_data *data, int chan)
4003f57a3b9SMatti Vaittinen {
4013f57a3b9SMatti Vaittinen 	unsigned int val, regval;
4023f57a3b9SMatti Vaittinen 	int ret;
4033f57a3b9SMatti Vaittinen 
4043f57a3b9SMatti Vaittinen 	/* See if already started */
4053f57a3b9SMatti Vaittinen 	ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, &val);
4063f57a3b9SMatti Vaittinen 	if (val & BIT(chan))
4073f57a3b9SMatti Vaittinen 		return 0;
4083f57a3b9SMatti Vaittinen 
4093f57a3b9SMatti Vaittinen 	/*
4103f57a3b9SMatti Vaittinen 	 * The sequencer must be stopped when channels are added/removed from
4113f57a3b9SMatti Vaittinen 	 * the list of the measured channels to ensure the new channel
4123f57a3b9SMatti Vaittinen 	 * configuration is used.
4133f57a3b9SMatti Vaittinen 	 */
4143f57a3b9SMatti Vaittinen 	ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG,
4153f57a3b9SMatti Vaittinen 				BD79124_MSK_SEQ_START);
4163f57a3b9SMatti Vaittinen 	if (ret)
4173f57a3b9SMatti Vaittinen 		return ret;
4183f57a3b9SMatti Vaittinen 
4193f57a3b9SMatti Vaittinen 	ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, val | BIT(chan));
4203f57a3b9SMatti Vaittinen 	if (ret)
4213f57a3b9SMatti Vaittinen 		return ret;
4223f57a3b9SMatti Vaittinen 
4233f57a3b9SMatti Vaittinen 	ret = regmap_set_bits(data->map, BD79124_REG_SEQ_CFG,
4243f57a3b9SMatti Vaittinen 			      BD79124_MSK_SEQ_START);
4253f57a3b9SMatti Vaittinen 	if (ret)
4263f57a3b9SMatti Vaittinen 		return ret;
4273f57a3b9SMatti Vaittinen 
4283f57a3b9SMatti Vaittinen 	/*
4293f57a3b9SMatti Vaittinen 	 * Start the measurement at the background. Don't bother checking if
4303f57a3b9SMatti Vaittinen 	 * it was started, regmap has cache.
4313f57a3b9SMatti Vaittinen 	 */
4323f57a3b9SMatti Vaittinen 	regval = FIELD_PREP(BD79124_MSK_CONV_MODE, BD79124_CONV_MODE_AUTO);
4333f57a3b9SMatti Vaittinen 
4343f57a3b9SMatti Vaittinen 	return regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG,
4353f57a3b9SMatti Vaittinen 				BD79124_MSK_CONV_MODE, regval);
4363f57a3b9SMatti Vaittinen }
4373f57a3b9SMatti Vaittinen 
bd79124_stop_measurement(struct bd79124_data * data,int chan)4383f57a3b9SMatti Vaittinen static int bd79124_stop_measurement(struct bd79124_data *data, int chan)
4393f57a3b9SMatti Vaittinen {
4403f57a3b9SMatti Vaittinen 	unsigned int enabled_chans;
4413f57a3b9SMatti Vaittinen 	int ret;
4423f57a3b9SMatti Vaittinen 
4433f57a3b9SMatti Vaittinen 	/* See if already stopped */
4443f57a3b9SMatti Vaittinen 	ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, &enabled_chans);
4453f57a3b9SMatti Vaittinen 	if (!(enabled_chans & BIT(chan)))
4463f57a3b9SMatti Vaittinen 		return 0;
4473f57a3b9SMatti Vaittinen 
4483f57a3b9SMatti Vaittinen 	ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG,
4493f57a3b9SMatti Vaittinen 				BD79124_MSK_SEQ_START);
4503f57a3b9SMatti Vaittinen 
4513f57a3b9SMatti Vaittinen 	/* Clear the channel from the measured channels */
4523f57a3b9SMatti Vaittinen 	enabled_chans &= ~BIT(chan);
4533f57a3b9SMatti Vaittinen 	ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS,
4543f57a3b9SMatti Vaittinen 			   enabled_chans);
4553f57a3b9SMatti Vaittinen 	if (ret)
4563f57a3b9SMatti Vaittinen 		return ret;
4573f57a3b9SMatti Vaittinen 
4583f57a3b9SMatti Vaittinen 	/*
4593f57a3b9SMatti Vaittinen 	 * Stop background conversion for power saving if it was the last
4603f57a3b9SMatti Vaittinen 	 * channel.
4613f57a3b9SMatti Vaittinen 	 */
4623f57a3b9SMatti Vaittinen 	if (!enabled_chans) {
4633f57a3b9SMatti Vaittinen 		int regval = FIELD_PREP(BD79124_MSK_CONV_MODE,
4643f57a3b9SMatti Vaittinen 					BD79124_CONV_MODE_MANSEQ);
4653f57a3b9SMatti Vaittinen 
4663f57a3b9SMatti Vaittinen 		ret = regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG,
4673f57a3b9SMatti Vaittinen 					 BD79124_MSK_CONV_MODE, regval);
4683f57a3b9SMatti Vaittinen 		if (ret)
4693f57a3b9SMatti Vaittinen 			return ret;
4703f57a3b9SMatti Vaittinen 	}
4713f57a3b9SMatti Vaittinen 
4723f57a3b9SMatti Vaittinen 	return regmap_set_bits(data->map, BD79124_REG_SEQ_CFG,
4733f57a3b9SMatti Vaittinen 			       BD79124_MSK_SEQ_START);
4743f57a3b9SMatti Vaittinen }
4753f57a3b9SMatti Vaittinen 
bd79124_read_event_config(struct iio_dev * iio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir)4763f57a3b9SMatti Vaittinen static int bd79124_read_event_config(struct iio_dev *iio_dev,
4773f57a3b9SMatti Vaittinen 				     const struct iio_chan_spec *chan,
4783f57a3b9SMatti Vaittinen 				     enum iio_event_type type,
4793f57a3b9SMatti Vaittinen 				     enum iio_event_direction dir)
4803f57a3b9SMatti Vaittinen {
4813f57a3b9SMatti Vaittinen 	struct bd79124_data *data = iio_priv(iio_dev);
4823f57a3b9SMatti Vaittinen 
4833f57a3b9SMatti Vaittinen 	if (chan->channel >= BD79124_MAX_NUM_CHANNELS)
4843f57a3b9SMatti Vaittinen 		return -EINVAL;
4853f57a3b9SMatti Vaittinen 
4863f57a3b9SMatti Vaittinen 	return !!(data->alarm_monitored[chan->channel] & BIT(dir));
4873f57a3b9SMatti Vaittinen }
4883f57a3b9SMatti Vaittinen 
bd79124_disable_event(struct bd79124_data * data,enum iio_event_direction dir,int channel)4893f57a3b9SMatti Vaittinen static int bd79124_disable_event(struct bd79124_data *data,
4903f57a3b9SMatti Vaittinen 				 enum iio_event_direction dir, int channel)
4913f57a3b9SMatti Vaittinen {
4923f57a3b9SMatti Vaittinen 	int dir_bit = BIT(dir);
4933f57a3b9SMatti Vaittinen 	int reg;
4943f57a3b9SMatti Vaittinen 	unsigned int limit;
4953f57a3b9SMatti Vaittinen 
4963f57a3b9SMatti Vaittinen 	guard(mutex)(&data->mutex);
4973f57a3b9SMatti Vaittinen 
4983f57a3b9SMatti Vaittinen 	/*
4993f57a3b9SMatti Vaittinen 	 * Set thresholds either to 0 or to 2^12 - 1 as appropriate to prevent
5003f57a3b9SMatti Vaittinen 	 * alerts and thus disable event generation.
5013f57a3b9SMatti Vaittinen 	 */
5023f57a3b9SMatti Vaittinen 	if (dir == IIO_EV_DIR_RISING) {
5033f57a3b9SMatti Vaittinen 		reg = BD79124_GET_HIGH_LIMIT_REG(channel);
5043f57a3b9SMatti Vaittinen 		limit = BD79124_HIGH_LIMIT_MAX;
5053f57a3b9SMatti Vaittinen 	} else if (dir == IIO_EV_DIR_FALLING) {
5063f57a3b9SMatti Vaittinen 		reg = BD79124_GET_LOW_LIMIT_REG(channel);
5073f57a3b9SMatti Vaittinen 		limit = BD79124_LOW_LIMIT_MIN;
5083f57a3b9SMatti Vaittinen 	} else {
5093f57a3b9SMatti Vaittinen 		return -EINVAL;
5103f57a3b9SMatti Vaittinen 	}
5113f57a3b9SMatti Vaittinen 
5123f57a3b9SMatti Vaittinen 	data->alarm_monitored[channel] &= ~dir_bit;
5133f57a3b9SMatti Vaittinen 
5143f57a3b9SMatti Vaittinen 	/*
5153f57a3b9SMatti Vaittinen 	 * Stop measurement if there is no more events to monitor.
5163f57a3b9SMatti Vaittinen 	 * We don't bother checking the retval because the limit
5173f57a3b9SMatti Vaittinen 	 * setting should in any case effectively disable the alarm.
5183f57a3b9SMatti Vaittinen 	 */
5193f57a3b9SMatti Vaittinen 	if (!data->alarm_monitored[channel]) {
5203f57a3b9SMatti Vaittinen 		bd79124_stop_measurement(data, channel);
5213f57a3b9SMatti Vaittinen 		regmap_clear_bits(data->map, BD79124_REG_ALERT_CH_SEL,
5223f57a3b9SMatti Vaittinen 				  BIT(channel));
5233f57a3b9SMatti Vaittinen 	}
5243f57a3b9SMatti Vaittinen 
5253f57a3b9SMatti Vaittinen 	return bd79124_write_int_to_reg(data, reg, limit);
5263f57a3b9SMatti Vaittinen }
5273f57a3b9SMatti Vaittinen 
bd79124_enable_event(struct bd79124_data * data,enum iio_event_direction dir,unsigned int channel)5283f57a3b9SMatti Vaittinen static int bd79124_enable_event(struct bd79124_data *data,
5293f57a3b9SMatti Vaittinen 				enum iio_event_direction dir,
5303f57a3b9SMatti Vaittinen 				unsigned int channel)
5313f57a3b9SMatti Vaittinen {
5323f57a3b9SMatti Vaittinen 	int dir_bit = BIT(dir);
5333f57a3b9SMatti Vaittinen 	int reg, ret;
5343f57a3b9SMatti Vaittinen 	u16 *limit;
5353f57a3b9SMatti Vaittinen 
5363f57a3b9SMatti Vaittinen 	guard(mutex)(&data->mutex);
5373f57a3b9SMatti Vaittinen 	ret = bd79124_start_measurement(data, channel);
5383f57a3b9SMatti Vaittinen 	if (ret)
5393f57a3b9SMatti Vaittinen 		return ret;
5403f57a3b9SMatti Vaittinen 
5413f57a3b9SMatti Vaittinen 	data->alarm_monitored[channel] |= dir_bit;
5423f57a3b9SMatti Vaittinen 
5433f57a3b9SMatti Vaittinen 	/* Add the channel to the list of monitored channels */
5443f57a3b9SMatti Vaittinen 	ret = regmap_set_bits(data->map, BD79124_REG_ALERT_CH_SEL, BIT(channel));
5453f57a3b9SMatti Vaittinen 	if (ret)
5463f57a3b9SMatti Vaittinen 		return ret;
5473f57a3b9SMatti Vaittinen 
5483f57a3b9SMatti Vaittinen 	if (dir == IIO_EV_DIR_RISING) {
5493f57a3b9SMatti Vaittinen 		limit = &data->alarm_f_limit[channel];
5503f57a3b9SMatti Vaittinen 		reg = BD79124_GET_HIGH_LIMIT_REG(channel);
5513f57a3b9SMatti Vaittinen 	} else {
5523f57a3b9SMatti Vaittinen 		limit = &data->alarm_f_limit[channel];
5533f57a3b9SMatti Vaittinen 		reg = BD79124_GET_LOW_LIMIT_REG(channel);
5543f57a3b9SMatti Vaittinen 	}
5553f57a3b9SMatti Vaittinen 	/*
5563f57a3b9SMatti Vaittinen 	 * Don't write the new limit to the hardware if we are in the
5573f57a3b9SMatti Vaittinen 	 * rate-limit period. The timer which re-enables the event will set
5583f57a3b9SMatti Vaittinen 	 * the limit.
5593f57a3b9SMatti Vaittinen 	 */
5603f57a3b9SMatti Vaittinen 	if (!(data->alarm_suppressed[channel] & dir_bit)) {
5613f57a3b9SMatti Vaittinen 		ret = bd79124_write_int_to_reg(data, reg, *limit);
5623f57a3b9SMatti Vaittinen 		if (ret)
5633f57a3b9SMatti Vaittinen 			return ret;
5643f57a3b9SMatti Vaittinen 	}
5653f57a3b9SMatti Vaittinen 
5663f57a3b9SMatti Vaittinen 	/*
5673f57a3b9SMatti Vaittinen 	 * Enable comparator. Trust the regmap cache, no need to check
5683f57a3b9SMatti Vaittinen 	 * if it was already enabled.
5693f57a3b9SMatti Vaittinen 	 *
5703f57a3b9SMatti Vaittinen 	 * We could do this in the hw-init, but there may be users who
5713f57a3b9SMatti Vaittinen 	 * never enable alarms and for them it makes sense to not
5723f57a3b9SMatti Vaittinen 	 * enable the comparator at probe.
5733f57a3b9SMatti Vaittinen 	 */
5743f57a3b9SMatti Vaittinen 	return regmap_set_bits(data->map, BD79124_REG_GEN_CFG,
5753f57a3b9SMatti Vaittinen 				      BD79124_MSK_DWC_EN);
5763f57a3b9SMatti Vaittinen }
5773f57a3b9SMatti Vaittinen 
bd79124_write_event_config(struct iio_dev * iio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,bool state)5783f57a3b9SMatti Vaittinen static int bd79124_write_event_config(struct iio_dev *iio_dev,
5793f57a3b9SMatti Vaittinen 				      const struct iio_chan_spec *chan,
5803f57a3b9SMatti Vaittinen 				      enum iio_event_type type,
5813f57a3b9SMatti Vaittinen 				      enum iio_event_direction dir, bool state)
5823f57a3b9SMatti Vaittinen {
5833f57a3b9SMatti Vaittinen 	struct bd79124_data *data = iio_priv(iio_dev);
5843f57a3b9SMatti Vaittinen 
5853f57a3b9SMatti Vaittinen 	if (chan->channel >= BD79124_MAX_NUM_CHANNELS)
5863f57a3b9SMatti Vaittinen 		return -EINVAL;
5873f57a3b9SMatti Vaittinen 
5883f57a3b9SMatti Vaittinen 	if (state)
5893f57a3b9SMatti Vaittinen 		return bd79124_enable_event(data, dir, chan->channel);
5903f57a3b9SMatti Vaittinen 
5913f57a3b9SMatti Vaittinen 	return bd79124_disable_event(data, dir, chan->channel);
5923f57a3b9SMatti Vaittinen }
5933f57a3b9SMatti Vaittinen 
bd79124_write_event_value(struct iio_dev * iio_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)5943f57a3b9SMatti Vaittinen static int bd79124_write_event_value(struct iio_dev *iio_dev,
5953f57a3b9SMatti Vaittinen 				     const struct iio_chan_spec *chan,
5963f57a3b9SMatti Vaittinen 				     enum iio_event_type type,
5973f57a3b9SMatti Vaittinen 				     enum iio_event_direction dir,
5983f57a3b9SMatti Vaittinen 				     enum iio_event_info info, int val,
5993f57a3b9SMatti Vaittinen 				     int val2)
6003f57a3b9SMatti Vaittinen {
6013f57a3b9SMatti Vaittinen 	struct bd79124_data *data = iio_priv(iio_dev);
6023f57a3b9SMatti Vaittinen 	int reg;
6033f57a3b9SMatti Vaittinen 
6043f57a3b9SMatti Vaittinen 	if (chan->channel >= BD79124_MAX_NUM_CHANNELS)
6053f57a3b9SMatti Vaittinen 		return -EINVAL;
6063f57a3b9SMatti Vaittinen 
6073f57a3b9SMatti Vaittinen 	switch (info) {
6083f57a3b9SMatti Vaittinen 	case IIO_EV_INFO_VALUE:
6093f57a3b9SMatti Vaittinen 	{
6103f57a3b9SMatti Vaittinen 		guard(mutex)(&data->mutex);
6113f57a3b9SMatti Vaittinen 
6123f57a3b9SMatti Vaittinen 		if (dir == IIO_EV_DIR_RISING) {
6133f57a3b9SMatti Vaittinen 			data->alarm_r_limit[chan->channel] = val;
6143f57a3b9SMatti Vaittinen 			reg = BD79124_GET_HIGH_LIMIT_REG(chan->channel);
6153f57a3b9SMatti Vaittinen 		} else if (dir == IIO_EV_DIR_FALLING) {
6163f57a3b9SMatti Vaittinen 			data->alarm_f_limit[chan->channel] = val;
6173f57a3b9SMatti Vaittinen 			reg = BD79124_GET_LOW_LIMIT_REG(chan->channel);
6183f57a3b9SMatti Vaittinen 		} else {
6193f57a3b9SMatti Vaittinen 			return -EINVAL;
6203f57a3b9SMatti Vaittinen 		}
6213f57a3b9SMatti Vaittinen 		/*
6223f57a3b9SMatti Vaittinen 		 * We don't want to enable the alarm if it is not enabled or
6233f57a3b9SMatti Vaittinen 		 * if it is suppressed. In that case skip writing to the
6243f57a3b9SMatti Vaittinen 		 * register.
6253f57a3b9SMatti Vaittinen 		 */
6263f57a3b9SMatti Vaittinen 		if (!(data->alarm_monitored[chan->channel] & BIT(dir)) ||
6273f57a3b9SMatti Vaittinen 		    data->alarm_suppressed[chan->channel] & BIT(dir))
6283f57a3b9SMatti Vaittinen 			return 0;
6293f57a3b9SMatti Vaittinen 
6303f57a3b9SMatti Vaittinen 		return bd79124_write_int_to_reg(data, reg, val);
6313f57a3b9SMatti Vaittinen 	}
6323f57a3b9SMatti Vaittinen 	case IIO_EV_INFO_HYSTERESIS:
6333f57a3b9SMatti Vaittinen 		reg = BD79124_GET_HYSTERESIS_REG(chan->channel);
6343f57a3b9SMatti Vaittinen 		val >>= 3;
6353f57a3b9SMatti Vaittinen 
6363f57a3b9SMatti Vaittinen 		return regmap_update_bits(data->map, reg, BD79124_MSK_HYSTERESIS,
6373f57a3b9SMatti Vaittinen 					  val);
6383f57a3b9SMatti Vaittinen 	default:
6393f57a3b9SMatti Vaittinen 		return -EINVAL;
6403f57a3b9SMatti Vaittinen 	}
6413f57a3b9SMatti Vaittinen }
6423f57a3b9SMatti Vaittinen 
bd79124_single_chan_seq(struct bd79124_data * data,int chan,unsigned int * old)6433f57a3b9SMatti Vaittinen static int bd79124_single_chan_seq(struct bd79124_data *data, int chan, unsigned int *old)
6443f57a3b9SMatti Vaittinen {
6453f57a3b9SMatti Vaittinen 	int ret;
6463f57a3b9SMatti Vaittinen 
6473f57a3b9SMatti Vaittinen 	ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG,
6483f57a3b9SMatti Vaittinen 				BD79124_MSK_SEQ_START);
6493f57a3b9SMatti Vaittinen 	if (ret)
6503f57a3b9SMatti Vaittinen 		return ret;
6513f57a3b9SMatti Vaittinen 
6523f57a3b9SMatti Vaittinen 	/*
6533f57a3b9SMatti Vaittinen 	 * It may be we have some channels monitored for alarms so we want to
6543f57a3b9SMatti Vaittinen 	 * cache the old config and return it when the single channel
6553f57a3b9SMatti Vaittinen 	 * measurement has been completed.
6563f57a3b9SMatti Vaittinen 	 */
6573f57a3b9SMatti Vaittinen 	ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, old);
6583f57a3b9SMatti Vaittinen 	if (ret)
6593f57a3b9SMatti Vaittinen 		return ret;
6603f57a3b9SMatti Vaittinen 
6613f57a3b9SMatti Vaittinen 	ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, BIT(chan));
6623f57a3b9SMatti Vaittinen 	if (ret)
6633f57a3b9SMatti Vaittinen 		return ret;
6643f57a3b9SMatti Vaittinen 
6653f57a3b9SMatti Vaittinen 	/* Restart the sequencer */
6663f57a3b9SMatti Vaittinen 	return regmap_set_bits(data->map, BD79124_REG_SEQ_CFG,
6673f57a3b9SMatti Vaittinen 			       BD79124_MSK_SEQ_START);
6683f57a3b9SMatti Vaittinen }
6693f57a3b9SMatti Vaittinen 
bd79124_single_chan_seq_end(struct bd79124_data * data,unsigned int old)6703f57a3b9SMatti Vaittinen static int bd79124_single_chan_seq_end(struct bd79124_data *data, unsigned int old)
6713f57a3b9SMatti Vaittinen {
6723f57a3b9SMatti Vaittinen 	int ret;
6733f57a3b9SMatti Vaittinen 
6743f57a3b9SMatti Vaittinen 	ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG,
6753f57a3b9SMatti Vaittinen 				BD79124_MSK_SEQ_START);
6763f57a3b9SMatti Vaittinen 	if (ret)
6773f57a3b9SMatti Vaittinen 		return ret;
6783f57a3b9SMatti Vaittinen 
6793f57a3b9SMatti Vaittinen 	ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, old);
6803f57a3b9SMatti Vaittinen 	if (ret)
6813f57a3b9SMatti Vaittinen 		return ret;
6823f57a3b9SMatti Vaittinen 
6833f57a3b9SMatti Vaittinen 	return regmap_set_bits(data->map, BD79124_REG_SEQ_CFG,
6843f57a3b9SMatti Vaittinen 			       BD79124_MSK_SEQ_START);
6853f57a3b9SMatti Vaittinen }
6863f57a3b9SMatti Vaittinen 
bd79124_read_raw(struct iio_dev * iio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long m)6873f57a3b9SMatti Vaittinen static int bd79124_read_raw(struct iio_dev *iio_dev,
6883f57a3b9SMatti Vaittinen 			    struct iio_chan_spec const *chan,
6893f57a3b9SMatti Vaittinen 			    int *val, int *val2, long m)
6903f57a3b9SMatti Vaittinen {
6913f57a3b9SMatti Vaittinen 	struct bd79124_data *data = iio_priv(iio_dev);
6923f57a3b9SMatti Vaittinen 	int ret;
6933f57a3b9SMatti Vaittinen 
6943f57a3b9SMatti Vaittinen 	if (chan->channel >= BD79124_MAX_NUM_CHANNELS)
6953f57a3b9SMatti Vaittinen 		return -EINVAL;
6963f57a3b9SMatti Vaittinen 
6973f57a3b9SMatti Vaittinen 	switch (m) {
6983f57a3b9SMatti Vaittinen 	case IIO_CHAN_INFO_RAW:
6993f57a3b9SMatti Vaittinen 	{
7003f57a3b9SMatti Vaittinen 		unsigned int old_chan_cfg, regval;
7013f57a3b9SMatti Vaittinen 		int tmp;
7023f57a3b9SMatti Vaittinen 
7033f57a3b9SMatti Vaittinen 		guard(mutex)(&data->mutex);
7043f57a3b9SMatti Vaittinen 
7053f57a3b9SMatti Vaittinen 		/*
7063f57a3b9SMatti Vaittinen 		 * Start the automatic conversion. This is needed here if no
7073f57a3b9SMatti Vaittinen 		 * events have been enabled.
7083f57a3b9SMatti Vaittinen 		 */
7093f57a3b9SMatti Vaittinen 		regval = FIELD_PREP(BD79124_MSK_CONV_MODE,
7103f57a3b9SMatti Vaittinen 				    BD79124_CONV_MODE_AUTO);
7113f57a3b9SMatti Vaittinen 		ret = regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG,
7123f57a3b9SMatti Vaittinen 					 BD79124_MSK_CONV_MODE, regval);
7133f57a3b9SMatti Vaittinen 		if (ret)
7143f57a3b9SMatti Vaittinen 			return ret;
7153f57a3b9SMatti Vaittinen 
7163f57a3b9SMatti Vaittinen 		ret = bd79124_single_chan_seq(data, chan->channel, &old_chan_cfg);
7173f57a3b9SMatti Vaittinen 		if (ret)
7183f57a3b9SMatti Vaittinen 			return ret;
7193f57a3b9SMatti Vaittinen 
7203f57a3b9SMatti Vaittinen 		/* The maximum conversion time is 6 uS. */
7213f57a3b9SMatti Vaittinen 		udelay(6);
7223f57a3b9SMatti Vaittinen 
7233f57a3b9SMatti Vaittinen 		ret = bd79124_read_reg_to_int(data,
7243f57a3b9SMatti Vaittinen 			BD79124_GET_RECENT_RES_REG(chan->channel), val);
7253f57a3b9SMatti Vaittinen 		/*
7263f57a3b9SMatti Vaittinen 		 * Return the old chan config even if data reading failed in
7273f57a3b9SMatti Vaittinen 		 * order to re-enable the event monitoring.
7283f57a3b9SMatti Vaittinen 		 */
7293f57a3b9SMatti Vaittinen 		tmp = bd79124_single_chan_seq_end(data, old_chan_cfg);
7303f57a3b9SMatti Vaittinen 		if (tmp)
7313f57a3b9SMatti Vaittinen 			dev_err(data->dev,
7323f57a3b9SMatti Vaittinen 				"Failed to return config. Alarms may be disabled\n");
7333f57a3b9SMatti Vaittinen 
7343f57a3b9SMatti Vaittinen 		if (ret)
7353f57a3b9SMatti Vaittinen 			return ret;
7363f57a3b9SMatti Vaittinen 
7373f57a3b9SMatti Vaittinen 		return IIO_VAL_INT;
7383f57a3b9SMatti Vaittinen 	}
7393f57a3b9SMatti Vaittinen 	case IIO_CHAN_INFO_SCALE:
7403f57a3b9SMatti Vaittinen 		*val = data->vmax / 1000;
7413f57a3b9SMatti Vaittinen 		*val2 = BD79124_ADC_BITS;
7423f57a3b9SMatti Vaittinen 		return IIO_VAL_FRACTIONAL_LOG2;
7433f57a3b9SMatti Vaittinen 	default:
7443f57a3b9SMatti Vaittinen 		return -EINVAL;
7453f57a3b9SMatti Vaittinen 	}
7463f57a3b9SMatti Vaittinen }
7473f57a3b9SMatti Vaittinen 
7483f57a3b9SMatti Vaittinen static const struct iio_info bd79124_info = {
7493f57a3b9SMatti Vaittinen 	.read_raw = bd79124_read_raw,
7503f57a3b9SMatti Vaittinen 	.read_event_config = &bd79124_read_event_config,
7513f57a3b9SMatti Vaittinen 	.write_event_config = &bd79124_write_event_config,
7523f57a3b9SMatti Vaittinen 	.read_event_value = &bd79124_read_event_value,
7533f57a3b9SMatti Vaittinen 	.write_event_value = &bd79124_write_event_value,
7543f57a3b9SMatti Vaittinen };
7553f57a3b9SMatti Vaittinen 
bd79124_re_enable_lo(struct bd79124_data * data,unsigned int channel)7563f57a3b9SMatti Vaittinen static void bd79124_re_enable_lo(struct bd79124_data *data, unsigned int channel)
7573f57a3b9SMatti Vaittinen {
7583f57a3b9SMatti Vaittinen 	int ret, evbit = BIT(IIO_EV_DIR_FALLING);
7593f57a3b9SMatti Vaittinen 
7603f57a3b9SMatti Vaittinen 	/*
7613f57a3b9SMatti Vaittinen 	 * We should not re-enable the event if user has disabled it while
7623f57a3b9SMatti Vaittinen 	 * rate-limiting was enabled.
7633f57a3b9SMatti Vaittinen 	 */
7643f57a3b9SMatti Vaittinen 	if (!(data->alarm_suppressed[channel] & evbit))
7653f57a3b9SMatti Vaittinen 		return;
7663f57a3b9SMatti Vaittinen 
7673f57a3b9SMatti Vaittinen 	data->alarm_suppressed[channel] &= ~evbit;
7683f57a3b9SMatti Vaittinen 
7693f57a3b9SMatti Vaittinen 	if (!(data->alarm_monitored[channel] & evbit))
7703f57a3b9SMatti Vaittinen 		return;
7713f57a3b9SMatti Vaittinen 
7723f57a3b9SMatti Vaittinen 	ret = bd79124_write_int_to_reg(data, BD79124_GET_LOW_LIMIT_REG(channel),
7733f57a3b9SMatti Vaittinen 				       data->alarm_f_limit[channel]);
7743f57a3b9SMatti Vaittinen 	if (ret)
7753f57a3b9SMatti Vaittinen 		dev_warn(data->dev, "Low limit enabling failed for channel%d\n",
7763f57a3b9SMatti Vaittinen 			 channel);
7773f57a3b9SMatti Vaittinen }
7783f57a3b9SMatti Vaittinen 
bd79124_re_enable_hi(struct bd79124_data * data,unsigned int channel)7793f57a3b9SMatti Vaittinen static void bd79124_re_enable_hi(struct bd79124_data *data, unsigned int channel)
7803f57a3b9SMatti Vaittinen {
7813f57a3b9SMatti Vaittinen 	int ret, evbit = BIT(IIO_EV_DIR_RISING);
7823f57a3b9SMatti Vaittinen 
7833f57a3b9SMatti Vaittinen 	/*
7843f57a3b9SMatti Vaittinen 	 * We should not re-enable the event if user has disabled it while
7853f57a3b9SMatti Vaittinen 	 * rate-limiting was enabled.
7863f57a3b9SMatti Vaittinen 	 */
7873f57a3b9SMatti Vaittinen 	if (!(data->alarm_suppressed[channel] & evbit))
7883f57a3b9SMatti Vaittinen 		return;
7893f57a3b9SMatti Vaittinen 
7903f57a3b9SMatti Vaittinen 	data->alarm_suppressed[channel] &= ~evbit;
7913f57a3b9SMatti Vaittinen 
7923f57a3b9SMatti Vaittinen 	if (!(data->alarm_monitored[channel] & evbit))
7933f57a3b9SMatti Vaittinen 		return;
7943f57a3b9SMatti Vaittinen 
7953f57a3b9SMatti Vaittinen 	ret = bd79124_write_int_to_reg(data, BD79124_GET_HIGH_LIMIT_REG(channel),
7963f57a3b9SMatti Vaittinen 				       data->alarm_r_limit[channel]);
7973f57a3b9SMatti Vaittinen 	if (ret)
7983f57a3b9SMatti Vaittinen 		dev_warn(data->dev, "High limit enabling failed for channel%d\n",
7993f57a3b9SMatti Vaittinen 			 channel);
8003f57a3b9SMatti Vaittinen }
8013f57a3b9SMatti Vaittinen 
bd79124_alm_enable_worker(struct work_struct * work)8023f57a3b9SMatti Vaittinen static void bd79124_alm_enable_worker(struct work_struct *work)
8033f57a3b9SMatti Vaittinen {
8043f57a3b9SMatti Vaittinen 	int i;
8053f57a3b9SMatti Vaittinen 	struct bd79124_data *data = container_of(work, struct bd79124_data,
8063f57a3b9SMatti Vaittinen 						 alm_enable_work.work);
8073f57a3b9SMatti Vaittinen 
8083f57a3b9SMatti Vaittinen 	/* Take the mutex so there is no race with user disabling the alarm */
8093f57a3b9SMatti Vaittinen 	guard(mutex)(&data->mutex);
8103f57a3b9SMatti Vaittinen 	for (i = 0; i < BD79124_MAX_NUM_CHANNELS; i++) {
8113f57a3b9SMatti Vaittinen 		bd79124_re_enable_hi(data, i);
8123f57a3b9SMatti Vaittinen 		bd79124_re_enable_lo(data, i);
8133f57a3b9SMatti Vaittinen 	}
8143f57a3b9SMatti Vaittinen }
8153f57a3b9SMatti Vaittinen 
__bd79124_event_ratelimit(struct bd79124_data * data,int reg,unsigned int limit)8163f57a3b9SMatti Vaittinen static int __bd79124_event_ratelimit(struct bd79124_data *data, int reg,
8173f57a3b9SMatti Vaittinen 				     unsigned int limit)
8183f57a3b9SMatti Vaittinen {
8193f57a3b9SMatti Vaittinen 	int ret;
8203f57a3b9SMatti Vaittinen 
8213f57a3b9SMatti Vaittinen 	if (limit > BD79124_HIGH_LIMIT_MAX)
8223f57a3b9SMatti Vaittinen 		return -EINVAL;
8233f57a3b9SMatti Vaittinen 
8243f57a3b9SMatti Vaittinen 	ret = bd79124_write_int_to_reg(data, reg, limit);
8253f57a3b9SMatti Vaittinen 	if (ret)
8263f57a3b9SMatti Vaittinen 		return ret;
8273f57a3b9SMatti Vaittinen 
8283f57a3b9SMatti Vaittinen 	/*
8293f57a3b9SMatti Vaittinen 	 * We use 1 sec 'grace period'. At the moment I see no reason to make
8303f57a3b9SMatti Vaittinen 	 * this user configurable. We need an ABI for this if configuration is
8313f57a3b9SMatti Vaittinen 	 * needed.
8323f57a3b9SMatti Vaittinen 	 */
8333f57a3b9SMatti Vaittinen 	schedule_delayed_work(&data->alm_enable_work, msecs_to_jiffies(1000));
8343f57a3b9SMatti Vaittinen 
8353f57a3b9SMatti Vaittinen 	return 0;
8363f57a3b9SMatti Vaittinen }
8373f57a3b9SMatti Vaittinen 
bd79124_event_ratelimit_hi(struct bd79124_data * data,unsigned int channel)8383f57a3b9SMatti Vaittinen static int bd79124_event_ratelimit_hi(struct bd79124_data *data,
8393f57a3b9SMatti Vaittinen 				      unsigned int channel)
8403f57a3b9SMatti Vaittinen {
8413f57a3b9SMatti Vaittinen 	guard(mutex)(&data->mutex);
8423f57a3b9SMatti Vaittinen 	data->alarm_suppressed[channel] |= BIT(IIO_EV_DIR_RISING);
8433f57a3b9SMatti Vaittinen 
8443f57a3b9SMatti Vaittinen 	return __bd79124_event_ratelimit(data,
8453f57a3b9SMatti Vaittinen 					 BD79124_GET_HIGH_LIMIT_REG(channel),
8463f57a3b9SMatti Vaittinen 					 BD79124_HIGH_LIMIT_MAX);
8473f57a3b9SMatti Vaittinen }
8483f57a3b9SMatti Vaittinen 
bd79124_event_ratelimit_lo(struct bd79124_data * data,unsigned int channel)8493f57a3b9SMatti Vaittinen static int bd79124_event_ratelimit_lo(struct bd79124_data *data,
8503f57a3b9SMatti Vaittinen 				      unsigned int channel)
8513f57a3b9SMatti Vaittinen {
8523f57a3b9SMatti Vaittinen 	guard(mutex)(&data->mutex);
8533f57a3b9SMatti Vaittinen 	data->alarm_suppressed[channel] |= BIT(IIO_EV_DIR_FALLING);
8543f57a3b9SMatti Vaittinen 
8553f57a3b9SMatti Vaittinen 	return __bd79124_event_ratelimit(data,
8563f57a3b9SMatti Vaittinen 					 BD79124_GET_LOW_LIMIT_REG(channel),
8573f57a3b9SMatti Vaittinen 					 BD79124_LOW_LIMIT_MIN);
8583f57a3b9SMatti Vaittinen }
8593f57a3b9SMatti Vaittinen 
bd79124_event_handler(int irq,void * priv)8603f57a3b9SMatti Vaittinen static irqreturn_t bd79124_event_handler(int irq, void *priv)
8613f57a3b9SMatti Vaittinen {
8623f57a3b9SMatti Vaittinen 	unsigned int i_hi, i_lo;
8633f57a3b9SMatti Vaittinen 	int i, ret;
8643f57a3b9SMatti Vaittinen 	struct iio_dev *iio_dev = priv;
8653f57a3b9SMatti Vaittinen 	struct bd79124_data *data = iio_priv(iio_dev);
8663f57a3b9SMatti Vaittinen 
8673f57a3b9SMatti Vaittinen 	/*
8683f57a3b9SMatti Vaittinen 	 * Return IRQ_NONE if bailing-out without acking. This allows the IRQ
8693f57a3b9SMatti Vaittinen 	 * subsystem to disable the offending IRQ line if we get a hardware
8703f57a3b9SMatti Vaittinen 	 * problem. This behaviour has saved my poor bottom a few times in the
8713f57a3b9SMatti Vaittinen 	 * past as, instead of getting unusably unresponsive, the system has
8723f57a3b9SMatti Vaittinen 	 * spilled out the magic words "...nobody cared".
8733f57a3b9SMatti Vaittinen 	 */
8743f57a3b9SMatti Vaittinen 	ret = regmap_read(data->map, BD79124_REG_EVENT_FLAG_HI, &i_hi);
8753f57a3b9SMatti Vaittinen 	if (ret)
8763f57a3b9SMatti Vaittinen 		return IRQ_NONE;
8773f57a3b9SMatti Vaittinen 
8783f57a3b9SMatti Vaittinen 	ret = regmap_read(data->map, BD79124_REG_EVENT_FLAG_LO, &i_lo);
8793f57a3b9SMatti Vaittinen 	if (ret)
8803f57a3b9SMatti Vaittinen 		return IRQ_NONE;
8813f57a3b9SMatti Vaittinen 
8823f57a3b9SMatti Vaittinen 	if (!i_lo && !i_hi)
8833f57a3b9SMatti Vaittinen 		return IRQ_NONE;
8843f57a3b9SMatti Vaittinen 
8853f57a3b9SMatti Vaittinen 	for (i = 0; i < BD79124_MAX_NUM_CHANNELS; i++) {
8863f57a3b9SMatti Vaittinen 		u64 ecode;
8873f57a3b9SMatti Vaittinen 
8883f57a3b9SMatti Vaittinen 		if (BIT(i) & i_hi) {
8893f57a3b9SMatti Vaittinen 			ecode = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
8903f57a3b9SMatti Vaittinen 						     IIO_EV_TYPE_THRESH,
8913f57a3b9SMatti Vaittinen 						     IIO_EV_DIR_RISING);
8923f57a3b9SMatti Vaittinen 
8933f57a3b9SMatti Vaittinen 			iio_push_event(iio_dev, ecode, data->timestamp);
8943f57a3b9SMatti Vaittinen 			/*
8953f57a3b9SMatti Vaittinen 			 * The BD79124 keeps the IRQ asserted for as long as
8963f57a3b9SMatti Vaittinen 			 * the voltage exceeds the threshold. It causes the IRQ
8973f57a3b9SMatti Vaittinen 			 * to keep firing.
8983f57a3b9SMatti Vaittinen 			 *
8993f57a3b9SMatti Vaittinen 			 * Disable the event for the channel and schedule the
9003f57a3b9SMatti Vaittinen 			 * re-enabling the event later to prevent storm of
9013f57a3b9SMatti Vaittinen 			 * events.
9023f57a3b9SMatti Vaittinen 			 */
9033f57a3b9SMatti Vaittinen 			ret = bd79124_event_ratelimit_hi(data, i);
9043f57a3b9SMatti Vaittinen 			if (ret)
9053f57a3b9SMatti Vaittinen 				return IRQ_NONE;
9063f57a3b9SMatti Vaittinen 		}
9073f57a3b9SMatti Vaittinen 		if (BIT(i) & i_lo) {
9083f57a3b9SMatti Vaittinen 			ecode = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
9093f57a3b9SMatti Vaittinen 						     IIO_EV_TYPE_THRESH,
9103f57a3b9SMatti Vaittinen 						     IIO_EV_DIR_FALLING);
9113f57a3b9SMatti Vaittinen 
9123f57a3b9SMatti Vaittinen 			iio_push_event(iio_dev, ecode, data->timestamp);
9133f57a3b9SMatti Vaittinen 			ret = bd79124_event_ratelimit_lo(data, i);
9143f57a3b9SMatti Vaittinen 			if (ret)
9153f57a3b9SMatti Vaittinen 				return IRQ_NONE;
9163f57a3b9SMatti Vaittinen 		}
9173f57a3b9SMatti Vaittinen 	}
9183f57a3b9SMatti Vaittinen 
9193f57a3b9SMatti Vaittinen 	ret = regmap_write(data->map, BD79124_REG_EVENT_FLAG_HI, i_hi);
9203f57a3b9SMatti Vaittinen 	if (ret)
9213f57a3b9SMatti Vaittinen 		return IRQ_NONE;
9223f57a3b9SMatti Vaittinen 
9233f57a3b9SMatti Vaittinen 	ret = regmap_write(data->map, BD79124_REG_EVENT_FLAG_LO, i_lo);
9243f57a3b9SMatti Vaittinen 	if (ret)
9253f57a3b9SMatti Vaittinen 		return IRQ_NONE;
9263f57a3b9SMatti Vaittinen 
9273f57a3b9SMatti Vaittinen 	return IRQ_HANDLED;
9283f57a3b9SMatti Vaittinen }
9293f57a3b9SMatti Vaittinen 
bd79124_irq_handler(int irq,void * priv)9303f57a3b9SMatti Vaittinen static irqreturn_t bd79124_irq_handler(int irq, void *priv)
9313f57a3b9SMatti Vaittinen {
9323f57a3b9SMatti Vaittinen 	struct iio_dev *iio_dev = priv;
9333f57a3b9SMatti Vaittinen 	struct bd79124_data *data = iio_priv(iio_dev);
9343f57a3b9SMatti Vaittinen 
9353f57a3b9SMatti Vaittinen 	data->timestamp = iio_get_time_ns(iio_dev);
9363f57a3b9SMatti Vaittinen 
9373f57a3b9SMatti Vaittinen 	return IRQ_WAKE_THREAD;
9383f57a3b9SMatti Vaittinen }
9393f57a3b9SMatti Vaittinen 
bd79124_chan_init(struct bd79124_data * data,int channel)9403f57a3b9SMatti Vaittinen static int bd79124_chan_init(struct bd79124_data *data, int channel)
9413f57a3b9SMatti Vaittinen {
9423f57a3b9SMatti Vaittinen 	int ret;
9433f57a3b9SMatti Vaittinen 
9443f57a3b9SMatti Vaittinen 	ret = regmap_write(data->map, BD79124_GET_HIGH_LIMIT_REG(channel),
9453f57a3b9SMatti Vaittinen 			   BD79124_HIGH_LIMIT_MAX);
9463f57a3b9SMatti Vaittinen 	if (ret)
9473f57a3b9SMatti Vaittinen 		return ret;
9483f57a3b9SMatti Vaittinen 
9493f57a3b9SMatti Vaittinen 	return regmap_write(data->map, BD79124_GET_LOW_LIMIT_REG(channel),
9503f57a3b9SMatti Vaittinen 			    BD79124_LOW_LIMIT_MIN);
9513f57a3b9SMatti Vaittinen }
9523f57a3b9SMatti Vaittinen 
bd79124_get_gpio_pins(const struct iio_chan_spec * cs,int num_channels)9533f57a3b9SMatti Vaittinen static int bd79124_get_gpio_pins(const struct iio_chan_spec *cs, int num_channels)
9543f57a3b9SMatti Vaittinen {
9553f57a3b9SMatti Vaittinen 	int i, gpio_channels;
9563f57a3b9SMatti Vaittinen 
9573f57a3b9SMatti Vaittinen 	/*
9583f57a3b9SMatti Vaittinen 	 * Let's initialize the mux config to say that all 8 channels are
9593f57a3b9SMatti Vaittinen 	 * GPIOs. Then we can just loop through the iio_chan_spec and clear the
9603f57a3b9SMatti Vaittinen 	 * bits for found ADC channels.
9613f57a3b9SMatti Vaittinen 	 */
9623f57a3b9SMatti Vaittinen 	gpio_channels = GENMASK(7, 0);
9633f57a3b9SMatti Vaittinen 	for (i = 0; i < num_channels; i++)
9643f57a3b9SMatti Vaittinen 		gpio_channels &= ~BIT(cs[i].channel);
9653f57a3b9SMatti Vaittinen 
9663f57a3b9SMatti Vaittinen 	return gpio_channels;
9673f57a3b9SMatti Vaittinen }
9683f57a3b9SMatti Vaittinen 
bd79124_hw_init(struct bd79124_data * data)9693f57a3b9SMatti Vaittinen static int bd79124_hw_init(struct bd79124_data *data)
9703f57a3b9SMatti Vaittinen {
9713f57a3b9SMatti Vaittinen 	unsigned int regval;
9723f57a3b9SMatti Vaittinen 	int ret, i;
9733f57a3b9SMatti Vaittinen 
9743f57a3b9SMatti Vaittinen 	for (i = 0; i < BD79124_MAX_NUM_CHANNELS; i++) {
9753f57a3b9SMatti Vaittinen 		ret = bd79124_chan_init(data, i);
9763f57a3b9SMatti Vaittinen 		if (ret)
9773f57a3b9SMatti Vaittinen 			return ret;
9783f57a3b9SMatti Vaittinen 		data->alarm_r_limit[i] = BD79124_HIGH_LIMIT_MAX;
9793f57a3b9SMatti Vaittinen 	}
9803f57a3b9SMatti Vaittinen 	/* Stop auto sequencer */
9813f57a3b9SMatti Vaittinen 	ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG,
9823f57a3b9SMatti Vaittinen 				BD79124_MSK_SEQ_START);
9833f57a3b9SMatti Vaittinen 	if (ret)
9843f57a3b9SMatti Vaittinen 		return ret;
9853f57a3b9SMatti Vaittinen 
9863f57a3b9SMatti Vaittinen 	/* Enable writing the measured values to the regsters */
9873f57a3b9SMatti Vaittinen 	ret = regmap_set_bits(data->map, BD79124_REG_GEN_CFG,
9883f57a3b9SMatti Vaittinen 			      BD79124_MSK_STATS_EN);
9893f57a3b9SMatti Vaittinen 	if (ret)
9903f57a3b9SMatti Vaittinen 		return ret;
9913f57a3b9SMatti Vaittinen 
9923f57a3b9SMatti Vaittinen 	/* Set no channels to be auto-measured */
9933f57a3b9SMatti Vaittinen 	ret = regmap_write(data->map, BD79124_REG_AUTO_CHANNELS, 0x0);
9943f57a3b9SMatti Vaittinen 	if (ret)
9953f57a3b9SMatti Vaittinen 		return ret;
9963f57a3b9SMatti Vaittinen 
9973f57a3b9SMatti Vaittinen 	/* Set no channels to be manually measured */
9983f57a3b9SMatti Vaittinen 	ret = regmap_write(data->map, BD79124_REG_MANUAL_CHANNELS, 0x0);
9993f57a3b9SMatti Vaittinen 	if (ret)
10003f57a3b9SMatti Vaittinen 		return ret;
10013f57a3b9SMatti Vaittinen 
10023f57a3b9SMatti Vaittinen 	regval = FIELD_PREP(BD79124_MSK_AUTO_INTERVAL, BD79124_INTERVAL_750_US);
10033f57a3b9SMatti Vaittinen 	ret = regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG,
10043f57a3b9SMatti Vaittinen 				 BD79124_MSK_AUTO_INTERVAL, regval);
10053f57a3b9SMatti Vaittinen 	if (ret)
10063f57a3b9SMatti Vaittinen 		return ret;
10073f57a3b9SMatti Vaittinen 
10083f57a3b9SMatti Vaittinen 	/* Sequencer mode to auto */
10093f57a3b9SMatti Vaittinen 	ret = regmap_set_bits(data->map, BD79124_REG_SEQ_CFG,
10103f57a3b9SMatti Vaittinen 			      BD79124_MSK_SEQ_SEQ);
10113f57a3b9SMatti Vaittinen 	if (ret)
10123f57a3b9SMatti Vaittinen 		return ret;
10133f57a3b9SMatti Vaittinen 
10143f57a3b9SMatti Vaittinen 	/* Don't start the measurement */
10153f57a3b9SMatti Vaittinen 	regval = FIELD_PREP(BD79124_MSK_CONV_MODE, BD79124_CONV_MODE_MANSEQ);
10163f57a3b9SMatti Vaittinen 	return regmap_update_bits(data->map, BD79124_REG_OPMODE_CFG,
10173f57a3b9SMatti Vaittinen 				  BD79124_MSK_CONV_MODE, regval);
10183f57a3b9SMatti Vaittinen }
10193f57a3b9SMatti Vaittinen 
bd79124_probe(struct i2c_client * i2c)10203f57a3b9SMatti Vaittinen static int bd79124_probe(struct i2c_client *i2c)
10213f57a3b9SMatti Vaittinen {
10223f57a3b9SMatti Vaittinen 	struct bd79124_data *data;
10233f57a3b9SMatti Vaittinen 	struct iio_dev *iio_dev;
10243f57a3b9SMatti Vaittinen 	const struct iio_chan_spec *template;
10253f57a3b9SMatti Vaittinen 	struct iio_chan_spec *cs;
10263f57a3b9SMatti Vaittinen 	struct device *dev = &i2c->dev;
10273f57a3b9SMatti Vaittinen 	unsigned int gpio_pins;
10283f57a3b9SMatti Vaittinen 	int ret;
10293f57a3b9SMatti Vaittinen 
10303f57a3b9SMatti Vaittinen 	iio_dev = devm_iio_device_alloc(dev, sizeof(*data));
10313f57a3b9SMatti Vaittinen 	if (!iio_dev)
10323f57a3b9SMatti Vaittinen 		return -ENOMEM;
10333f57a3b9SMatti Vaittinen 
10343f57a3b9SMatti Vaittinen 	data = iio_priv(iio_dev);
10353f57a3b9SMatti Vaittinen 	data->dev = dev;
10363f57a3b9SMatti Vaittinen 	data->map = devm_regmap_init_i2c(i2c, &bd79124_regmap);
10373f57a3b9SMatti Vaittinen 	if (IS_ERR(data->map))
10383f57a3b9SMatti Vaittinen 		return dev_err_probe(dev, PTR_ERR(data->map),
10393f57a3b9SMatti Vaittinen 				     "Failed to initialize Regmap\n");
10403f57a3b9SMatti Vaittinen 
10413f57a3b9SMatti Vaittinen 	ret = devm_regulator_get_enable_read_voltage(dev, "vdd");
10423f57a3b9SMatti Vaittinen 	if (ret < 0)
10433f57a3b9SMatti Vaittinen 		return dev_err_probe(dev, ret, "Failed to get the Vdd\n");
10443f57a3b9SMatti Vaittinen 
10453f57a3b9SMatti Vaittinen 	data->vmax = ret;
10463f57a3b9SMatti Vaittinen 
10473f57a3b9SMatti Vaittinen 	ret = devm_regulator_get_enable(dev, "iovdd");
10483f57a3b9SMatti Vaittinen 	if (ret < 0)
10493f57a3b9SMatti Vaittinen 		return dev_err_probe(dev, ret, "Failed to enable I/O voltage\n");
10503f57a3b9SMatti Vaittinen 
10513f57a3b9SMatti Vaittinen 	ret = devm_delayed_work_autocancel(dev, &data->alm_enable_work,
10523f57a3b9SMatti Vaittinen 					   bd79124_alm_enable_worker);
10533f57a3b9SMatti Vaittinen 	if (ret)
10543f57a3b9SMatti Vaittinen 		return ret;
10553f57a3b9SMatti Vaittinen 
10563f57a3b9SMatti Vaittinen 	if (i2c->irq) {
10573f57a3b9SMatti Vaittinen 		template = &bd79124_chan_template;
10583f57a3b9SMatti Vaittinen 	} else {
10593f57a3b9SMatti Vaittinen 		template = &bd79124_chan_template_noirq;
10603f57a3b9SMatti Vaittinen 		dev_dbg(dev, "No IRQ found, events disabled\n");
10613f57a3b9SMatti Vaittinen 	}
10623f57a3b9SMatti Vaittinen 
10633f57a3b9SMatti Vaittinen 	ret = devm_mutex_init(dev, &data->mutex);
10643f57a3b9SMatti Vaittinen 	if (ret)
10653f57a3b9SMatti Vaittinen 		return ret;
10663f57a3b9SMatti Vaittinen 
10673f57a3b9SMatti Vaittinen 	ret = devm_iio_adc_device_alloc_chaninfo_se(dev, template,
10683f57a3b9SMatti Vaittinen 		BD79124_MAX_NUM_CHANNELS - 1, &cs);
10693f57a3b9SMatti Vaittinen 	if (ret < 0) {
10703f57a3b9SMatti Vaittinen 		/* Register all pins as GPOs if there are no ADC channels */
10713f57a3b9SMatti Vaittinen 		if (ret == -ENOENT)
10723f57a3b9SMatti Vaittinen 			goto register_gpios;
10733f57a3b9SMatti Vaittinen 		return ret;
10743f57a3b9SMatti Vaittinen 	}
10753f57a3b9SMatti Vaittinen 	iio_dev->channels = cs;
10763f57a3b9SMatti Vaittinen 	iio_dev->num_channels = ret;
10773f57a3b9SMatti Vaittinen 	iio_dev->info = &bd79124_info;
10783f57a3b9SMatti Vaittinen 	iio_dev->name = "bd79124";
10793f57a3b9SMatti Vaittinen 	iio_dev->modes = INDIO_DIRECT_MODE;
10803f57a3b9SMatti Vaittinen 
10813f57a3b9SMatti Vaittinen 	ret = bd79124_hw_init(data);
10823f57a3b9SMatti Vaittinen 	if (ret)
10833f57a3b9SMatti Vaittinen 		return ret;
10843f57a3b9SMatti Vaittinen 
10853f57a3b9SMatti Vaittinen 	if (i2c->irq > 0) {
10863f57a3b9SMatti Vaittinen 		ret = devm_request_threaded_irq(dev, i2c->irq,
10873f57a3b9SMatti Vaittinen 			bd79124_irq_handler, &bd79124_event_handler,
10883f57a3b9SMatti Vaittinen 			IRQF_ONESHOT, "adc-thresh-alert", iio_dev);
10893f57a3b9SMatti Vaittinen 		if (ret)
10903f57a3b9SMatti Vaittinen 			return dev_err_probe(data->dev, ret,
10913f57a3b9SMatti Vaittinen 					     "Failed to register IRQ\n");
10923f57a3b9SMatti Vaittinen 	}
10933f57a3b9SMatti Vaittinen 
10943f57a3b9SMatti Vaittinen 	ret = devm_iio_device_register(data->dev, iio_dev);
10953f57a3b9SMatti Vaittinen 	if (ret)
10963f57a3b9SMatti Vaittinen 		return dev_err_probe(data->dev, ret, "Failed to register ADC\n");
10973f57a3b9SMatti Vaittinen 
10983f57a3b9SMatti Vaittinen register_gpios:
10993f57a3b9SMatti Vaittinen 	gpio_pins = bd79124_get_gpio_pins(iio_dev->channels,
11003f57a3b9SMatti Vaittinen 					  iio_dev->num_channels);
11013f57a3b9SMatti Vaittinen 
11023f57a3b9SMatti Vaittinen 	/*
11033f57a3b9SMatti Vaittinen 	 * The mux should default to "all ADCs", but better to not trust it.
11043f57a3b9SMatti Vaittinen 	 * Thus we do set the mux even when we have only ADCs and no GPOs.
11053f57a3b9SMatti Vaittinen 	 */
11063f57a3b9SMatti Vaittinen 	ret = regmap_write(data->map, BD79124_REG_PINCFG, gpio_pins);
11073f57a3b9SMatti Vaittinen 	if (ret)
11083f57a3b9SMatti Vaittinen 		return ret;
11093f57a3b9SMatti Vaittinen 
11103f57a3b9SMatti Vaittinen 	/* No GPOs if all channels are reserved for ADC, so we're done. */
11113f57a3b9SMatti Vaittinen 	if (!gpio_pins)
11123f57a3b9SMatti Vaittinen 		return 0;
11133f57a3b9SMatti Vaittinen 
11143f57a3b9SMatti Vaittinen 	data->gpio_valid_mask = gpio_pins;
11153f57a3b9SMatti Vaittinen 	data->gc = bd79124gpo_chip;
11163f57a3b9SMatti Vaittinen 	data->gc.parent = dev;
11173f57a3b9SMatti Vaittinen 
11183f57a3b9SMatti Vaittinen 	return devm_gpiochip_add_data(dev, &data->gc, data);
11193f57a3b9SMatti Vaittinen }
11203f57a3b9SMatti Vaittinen 
11213f57a3b9SMatti Vaittinen static const struct of_device_id bd79124_of_match[] = {
11223f57a3b9SMatti Vaittinen 	{ .compatible = "rohm,bd79124" },
11233f57a3b9SMatti Vaittinen 	{ }
11243f57a3b9SMatti Vaittinen };
11253f57a3b9SMatti Vaittinen MODULE_DEVICE_TABLE(of, bd79124_of_match);
11263f57a3b9SMatti Vaittinen 
11273f57a3b9SMatti Vaittinen static const struct i2c_device_id bd79124_id[] = {
11283f57a3b9SMatti Vaittinen 	{ "bd79124" },
11293f57a3b9SMatti Vaittinen 	{ }
11303f57a3b9SMatti Vaittinen };
11313f57a3b9SMatti Vaittinen MODULE_DEVICE_TABLE(i2c, bd79124_id);
11323f57a3b9SMatti Vaittinen 
11333f57a3b9SMatti Vaittinen static struct i2c_driver bd79124_driver = {
11343f57a3b9SMatti Vaittinen 	.driver = {
11353f57a3b9SMatti Vaittinen 		.name = "bd79124",
11363f57a3b9SMatti Vaittinen 		.of_match_table = bd79124_of_match,
11373f57a3b9SMatti Vaittinen 	},
11383f57a3b9SMatti Vaittinen 	.probe = bd79124_probe,
11393f57a3b9SMatti Vaittinen 	.id_table = bd79124_id,
11403f57a3b9SMatti Vaittinen };
11413f57a3b9SMatti Vaittinen module_i2c_driver(bd79124_driver);
11423f57a3b9SMatti Vaittinen 
11433f57a3b9SMatti Vaittinen MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
11443f57a3b9SMatti Vaittinen MODULE_DESCRIPTION("Driver for ROHM BD79124 ADC");
11453f57a3b9SMatti Vaittinen MODULE_LICENSE("GPL");
11463f57a3b9SMatti Vaittinen MODULE_IMPORT_NS("IIO_DRIVER");
1147