diff --git a/drivers/iio/accel/adxl345_core.c b/drivers/iio/accel/adxl345_core.c
index 7831ec511941..f9e5f47ba303 100644
--- a/drivers/iio/accel/adxl345_core.c
+++ b/drivers/iio/accel/adxl345_core.c
@@ -129,6 +129,29 @@ enum adxl345_axis {
 	ADXL345_TAP_SUPPRESS = BIT(3),
 };
 
+/* single/double tap */
+enum adxl345_tap_type {
+	ADXL345_SINGLE_TAP,
+	ADXL345_DOUBLE_TAP
+};
+
+static const unsigned int adxl345_tap_int_reg[2] = {
+	[ADXL345_SINGLE_TAP] = ADXL345_INT_SINGLE_TAP,
+	[ADXL345_DOUBLE_TAP] = ADXL345_INT_DOUBLE_TAP,
+};
+
+enum adxl345_tap_time_type {
+	ADXL345_TAP_TIME_LATENT,
+	ADXL345_TAP_TIME_WINDOW,
+	ADXL345_TAP_TIME_DUR
+};
+
+static const unsigned int adxl345_tap_time_reg[3] = {
+	[ADXL345_TAP_TIME_LATENT] = ADXL345_REG_LATENT,
+	[ADXL345_TAP_TIME_WINDOW] = ADXL345_REG_WINDOW,
+	[ADXL345_TAP_TIME_DUR] = ADXL345_REG_DUR,
+};
+
 struct adxl345_state {
 	const struct adxl345_chip_info *info;
 	struct regmap *regmap;
@@ -142,6 +165,8 @@ struct adxl345_state {
 	u32 tap_axis_ctrl;
 	u8 tap_threshold;
 	u32 tap_duration_us;
+	u32 tap_latent_us;
+	u32 tap_window_us;
 
 	__le16 fifo_buf[ADXL345_DIRS * ADXL345_FIFO_SIZE + 1] __aligned(IIO_DMA_MINALIGN);
 };
@@ -154,6 +179,12 @@ static struct iio_event_spec adxl345_events[] = {
 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
 		.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
 	},
+	{
+		/* double tap */
+		.type = IIO_EV_TYPE_GESTURE,
+		.dir = IIO_EV_DIR_DOUBLETAP,
+		.mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE),
+	},
 };
 
 #define ADXL345_CHANNEL(index, reg, axis) {					\
@@ -250,10 +281,12 @@ static int adxl345_write_tap_axis(struct adxl345_state *st,
 					     st->tap_axis_ctrl));
 }
 
-static int _adxl345_set_tap_int(struct adxl345_state *st, bool state)
+static int _adxl345_set_tap_int(struct adxl345_state *st,
+				enum adxl345_tap_type type, bool state)
 {
 	bool axis_valid;
 	bool singletap_args_valid = false;
+	bool doubletap_args_valid = false;
 	bool en = false;
 
 	axis_valid = FIELD_GET(ADXL345_REG_TAP_AXIS_MSK, st->tap_axis_ctrl) > 0;
@@ -264,14 +297,24 @@ static int _adxl345_set_tap_int(struct adxl345_state *st, bool state)
 	 */
 	singletap_args_valid = st->tap_threshold > 0 && st->tap_duration_us > 0;
 
-	en = axis_valid && singletap_args_valid;
+	if (type == ADXL345_SINGLE_TAP) {
+		en = axis_valid && singletap_args_valid;
+	} else {
+		/* doubletap: Window must be equal or greater than latent! */
+		doubletap_args_valid = st->tap_latent_us > 0 &&
+			st->tap_window_us > 0 &&
+			st->tap_window_us >= st->tap_latent_us;
+
+		en = axis_valid && singletap_args_valid && doubletap_args_valid;
+	}
 
-	adxl345_intmap_switch_bit(st, state && en, ADXL345_INT_SINGLE_TAP);
+	adxl345_intmap_switch_bit(st, state && en, adxl345_tap_int_reg[type]);
 
 	return adxl345_write_interrupts(st);
 }
 
-static int adxl345_is_tap_en(struct adxl345_state *st, bool *en)
+static int adxl345_is_tap_en(struct adxl345_state *st,
+			     enum adxl345_tap_type type, bool *en)
 {
 	int ret;
 	unsigned int regval;
@@ -280,7 +323,8 @@ static int adxl345_is_tap_en(struct adxl345_state *st, bool *en)
 	if (ret)
 		return ret;
 
-	*en = FIELD_GET(ADXL345_INT_SINGLE_TAP, regval) > 0;
+	// TODO FIELD_GET() seems not possible here due to construct 'not const', any ideas?
+	*en = (adxl345_tap_int_reg[type] & regval) > 0;
 
 	return 0;
 }
@@ -294,7 +338,12 @@ static int adxl345_set_singletap_en(struct adxl345_state *st,
 	if (ret)
 		return ret;
 
-	return _adxl345_set_tap_int(st, en);
+	return _adxl345_set_tap_int(st, ADXL345_SINGLE_TAP, en);
+}
+
+static int adxl345_set_doubletap_en(struct adxl345_state *st, bool en)
+{
+	return _adxl345_set_tap_int(st, ADXL345_DOUBLE_TAP, en);
 }
 
 static int adxl345_set_tap_value(struct adxl345_state *st, u8 val)
@@ -304,19 +353,33 @@ static int adxl345_set_tap_value(struct adxl345_state *st, u8 val)
 	return regmap_write(st->regmap, ADXL345_REG_THRESH_TAP, min(val, 0xFF));
 }
 
-static int _adxl345_set_tap_time(struct adxl345_state *st, u32 val_us)
+static int _adxl345_set_tap_time(struct adxl345_state *st,
+				 enum adxl345_tap_time_type type, u32 val_us)
 {
 	unsigned int regval;
 
-	st->tap_duration_us = val_us;
+	switch (type) {
+	case ADXL345_TAP_TIME_WINDOW:
+		st->tap_window_us = val_us;
+		break;
+	case ADXL345_TAP_TIME_LATENT:
+		st->tap_latent_us = val_us;
+		break;
+	case ADXL345_TAP_TIME_DUR:
+		st->tap_duration_us = val_us;
+		break;
+	}
 
 	/*
 	 * The scale factor is 1250us / LSB for tap_window_us and tap_latent_us.
 	 * For tap_duration_us the scale factor is 625us / LSB.
 	 */
-	regval = DIV_ROUND_CLOSEST(val_us, 625);
+	if (type == ADXL345_TAP_TIME_DUR)
+		regval = DIV_ROUND_CLOSEST(val_us, 625);
+	else
+		regval = DIV_ROUND_CLOSEST(val_us, 1250);
 
-	return regmap_write(st->regmap, ADXL345_REG_DUR, regval);
+	return regmap_write(st->regmap, adxl345_tap_time_reg[type], regval);
 }
 
 static int adxl345_set_tap_duration(struct adxl345_state *st, u32 val_int,
@@ -330,7 +393,35 @@ static int adxl345_set_tap_duration(struct adxl345_state *st, u32 val_int,
 	if (val_int || val_fract_us > 159375)
 		return -EINVAL;
 
-	return _adxl345_set_tap_time(st, val_fract_us);
+	return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_DUR, val_fract_us);
+}
+
+static int adxl345_set_tap_window(struct adxl345_state *st, u32 val_int,
+				  u32 val_fract_us)
+{
+	/*
+	 * Max value is 255 * 1250 us = 0.318750 seconds
+	 *
+	 * Note: the scaling is similar to the scaling in the ADXL380
+	 */
+	if (val_int || val_fract_us > 318750)
+		return -EINVAL;
+
+	return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_WINDOW, val_fract_us);
+}
+
+static int adxl345_set_tap_latent(struct adxl345_state *st, u32 val_int,
+				  u32 val_fract_us)
+{
+	/*
+	 * Max value is 255 * 1250 us = 0.318750 seconds
+	 *
+	 * Note: the scaling is similar to the scaling in the ADXL380
+	 */
+	if (val_int || val_fract_us > 318750)
+		return -EINVAL;
+
+	return _adxl345_set_tap_time(st, ADXL345_TAP_TIME_LATENT, val_fract_us);
 }
 
 static int adxl345_read_raw(struct iio_dev *indio_dev,
@@ -448,10 +539,15 @@ static int adxl345_read_event_config(struct iio_dev *indio_dev,
 				return -EINVAL;
 			}
 
-			ret = adxl345_is_tap_en(st, &int_en);
+			ret = adxl345_is_tap_en(st, ADXL345_SINGLE_TAP, &int_en);
 			if (ret)
 				return ret;
 			return int_en && axis_en;
+		case IIO_EV_DIR_DOUBLETAP:
+			ret = adxl345_is_tap_en(st, ADXL345_DOUBLE_TAP, &int_en);
+			if (ret)
+				return ret;
+			return int_en;
 		default:
 			return -EINVAL;
 		}
@@ -491,6 +587,8 @@ static int adxl345_write_event_config(struct iio_dev *indio_dev,
 		}
 
 		return adxl345_set_singletap_en(st, axis, state);
+	case IIO_EV_DIR_DOUBLETAP:
+		return adxl345_set_doubletap_en(st, state);
 	default:
 		return -EINVAL;
 	}
@@ -637,9 +735,13 @@ static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
 	static IIO_DEVICE_ATTR_RW(in_accel_##A##_##C##_##E, 0)
 
 ADXL345_generate_iio_dev_attr_FRACTIONAL(gesture_singletap, tap, duration, MICRO, us);
+ADXL345_generate_iio_dev_attr_FRACTIONAL(gesture_doubletap, tap, window, MICRO, us);
+ADXL345_generate_iio_dev_attr_FRACTIONAL(gesture_doubletap, tap, latent, MICRO, us);
 
 static struct attribute *adxl345_event_attrs[] = {
 	&iio_dev_attr_in_accel_gesture_singletap_duration_us.dev_attr.attr,
+	&iio_dev_attr_in_accel_gesture_doubletap_latent_us.dev_attr.attr,
+	&iio_dev_attr_in_accel_gesture_doubletap_window_us.dev_attr.attr,
 	NULL
 };
 
@@ -861,6 +963,17 @@ static int adxl345_push_event(struct iio_dev *indio_dev, int int_stat,
 			return ret;
 	}
 
+	if (FIELD_GET(ADXL345_INT_DOUBLE_TAP, int_stat)) {
+		ret = iio_push_event(indio_dev,
+				     IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
+							act_tap_dir,
+							IIO_EV_TYPE_GESTURE,
+							IIO_EV_DIR_DOUBLETAP),
+				     ts);
+		if (ret)
+			return ret;
+	}
+
 	return -ENOENT;
 }
 
@@ -965,6 +1078,8 @@ int adxl345_core_probe(struct device *dev, struct regmap *regmap,
 	/* Init with reasonable values */
 	st->tap_threshold = 35;			/*   35 [0x23]            */
 	st->tap_duration_us = 3;		/*    3 [0x03] -> .001875 */
+	st->tap_window_us = 20;			/*   20 [0x14] -> .025    */
+	st->tap_latent_us = 20;			/*   20 [0x14] -> .025    */
 
 	indio_dev->name = st->info->name;
 	indio_dev->info = &adxl345_info;
