forked from mirrors/linux
		
	gpiolib: cdev: consolidate edge detector configuration flags
Combine the polarity_change flag, struct line eflags, and hte enable flag into a single flag variable. The combination of these flags describes the configuration state of the edge detector, so formalize and clarify that by combining them into a single variable, edflags, in struct line. The edflags is a subset of the GPIO_V2_LINE_FLAGsb relevant to the edge detector, and is also a superset of the eflags it replaces. The eflags name is still used to describe the subset of edflags corresponding to the rising/falling edge flags where edflags is masked down to that subset. This consolidation reduces the number of variables being passed, simplifies state comparisons, and provides a more extensible foundation should additional edge sources be integrated in the future. Signed-off-by: Kent Gibson <warthog618@gmail.com> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
This commit is contained in:
		
							parent
							
								
									242202329f
								
							
						
					
					
						commit
						b1a92e9456
					
				
					 1 changed files with 60 additions and 66 deletions
				
			
		|  | @ -430,12 +430,15 @@ struct line { | |||
| 	struct linereq *req; | ||||
| 	unsigned int irq; | ||||
| 	/*
 | ||||
| 	 * eflags is set by edge_detector_setup(), edge_detector_stop() and | ||||
| 	 * edge_detector_update(), which are themselves mutually exclusive, | ||||
| 	 * and is accessed by edge_irq_thread() and debounce_work_func(), | ||||
| 	 * which can both live with a slightly stale value. | ||||
| 	 * The flags for the active edge detector configuration. | ||||
| 	 * | ||||
| 	 * edflags is set by linereq_create(), linereq_free(), and | ||||
| 	 * linereq_set_config_unlocked(), which are themselves mutually | ||||
| 	 * exclusive, and is accessed by edge_irq_thread(), | ||||
| 	 * process_hw_ts_thread() and debounce_work_func(), | ||||
| 	 * which can all live with a slightly stale value. | ||||
| 	 */ | ||||
| 	u64 eflags; | ||||
| 	u64 edflags; | ||||
| 	/*
 | ||||
| 	 * timestamp_ns and req_seqno are accessed only by | ||||
| 	 * edge_irq_handler() and edge_irq_thread(), which are themselves | ||||
|  | @ -541,6 +544,12 @@ struct linereq { | |||
| 	 GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \ | ||||
| 	 GPIO_V2_LINE_BIAS_FLAGS) | ||||
| 
 | ||||
| /* subset of flags relevant for edge detector configuration */ | ||||
| #define GPIO_V2_LINE_EDGE_DETECTOR_FLAGS \ | ||||
| 	(GPIO_V2_LINE_FLAG_ACTIVE_LOW | \ | ||||
| 	 GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \ | ||||
| 	 GPIO_V2_LINE_EDGE_FLAGS) | ||||
| 
 | ||||
| static void linereq_put_event(struct linereq *lr, | ||||
| 			      struct gpio_v2_line_event *le) | ||||
| { | ||||
|  | @ -580,8 +589,8 @@ static enum hte_return process_hw_ts_thread(void *p) | |||
| 	struct line *line; | ||||
| 	struct linereq *lr; | ||||
| 	struct gpio_v2_line_event le; | ||||
| 	u64 edflags; | ||||
| 	int level; | ||||
| 	u64 eflags; | ||||
| 
 | ||||
| 	if (!p) | ||||
| 		return HTE_CB_HANDLED; | ||||
|  | @ -592,15 +601,15 @@ static enum hte_return process_hw_ts_thread(void *p) | |||
| 	memset(&le, 0, sizeof(le)); | ||||
| 
 | ||||
| 	le.timestamp_ns = line->timestamp_ns; | ||||
| 	eflags = READ_ONCE(line->eflags); | ||||
| 	edflags = READ_ONCE(line->edflags); | ||||
| 
 | ||||
| 	switch (eflags) { | ||||
| 	switch (edflags & GPIO_V2_LINE_EDGE_FLAGS) { | ||||
| 	case GPIO_V2_LINE_FLAG_EDGE_BOTH: | ||||
| 		level = (line->raw_level >= 0) ? | ||||
| 				line->raw_level : | ||||
| 				gpiod_get_raw_value_cansleep(line->desc); | ||||
| 
 | ||||
| 		if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags)) | ||||
| 		if (edflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) | ||||
| 			level = !level; | ||||
| 
 | ||||
| 		le.id = line_event_id(level); | ||||
|  | @ -681,7 +690,7 @@ static irqreturn_t edge_irq_thread(int irq, void *p) | |||
| 	} | ||||
| 	line->timestamp_ns = 0; | ||||
| 
 | ||||
| 	switch (READ_ONCE(line->eflags)) { | ||||
| 	switch (READ_ONCE(line->edflags) & GPIO_V2_LINE_EDGE_FLAGS) { | ||||
| 	case GPIO_V2_LINE_FLAG_EDGE_BOTH: | ||||
| 		le.id = line_event_id(gpiod_get_value_cansleep(line->desc)); | ||||
| 		break; | ||||
|  | @ -756,16 +765,13 @@ static void debounce_work_func(struct work_struct *work) | |||
| 	struct gpio_v2_line_event le; | ||||
| 	struct line *line = container_of(work, struct line, work.work); | ||||
| 	struct linereq *lr; | ||||
| 	int level, diff_seqno; | ||||
| 	u64 eflags; | ||||
| 	u64 eflags, edflags = READ_ONCE(line->edflags); | ||||
| 	int level = -1, diff_seqno; | ||||
| 
 | ||||
| 	if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) { | ||||
| 	if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) | ||||
| 		level = line->raw_level; | ||||
| 	if (level < 0) | ||||
| 		level = gpiod_get_raw_value_cansleep(line->desc); | ||||
| 	} else { | ||||
| 		level = gpiod_get_raw_value_cansleep(line->desc); | ||||
| 	} | ||||
| 	if (level < 0) { | ||||
| 		pr_debug_ratelimited("debouncer failed to read line value\n"); | ||||
| 		return; | ||||
|  | @ -777,12 +783,12 @@ static void debounce_work_func(struct work_struct *work) | |||
| 	WRITE_ONCE(line->level, level); | ||||
| 
 | ||||
| 	/* -- edge detection -- */ | ||||
| 	eflags = READ_ONCE(line->eflags); | ||||
| 	eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS; | ||||
| 	if (!eflags) | ||||
| 		return; | ||||
| 
 | ||||
| 	/* switch from physical level to logical - if they differ */ | ||||
| 	if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags)) | ||||
| 	if (edflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) | ||||
| 		level = !level; | ||||
| 
 | ||||
| 	/* ignore edges that are not being monitored */ | ||||
|  | @ -796,7 +802,7 @@ static void debounce_work_func(struct work_struct *work) | |||
| 	lr = line->req; | ||||
| 	le.timestamp_ns = line_event_timestamp(line); | ||||
| 	le.offset = gpio_chip_hwgpio(line->desc); | ||||
| 	if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) { | ||||
| 	if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) { | ||||
| 		/* discard events except the last one */ | ||||
| 		line->total_discard_seq -= 1; | ||||
| 		diff_seqno = line->last_seqno - line->total_discard_seq - | ||||
|  | @ -843,8 +849,7 @@ static int hte_edge_setup(struct line *line, u64 eflags) | |||
| 				 process_hw_ts_thread, line); | ||||
| } | ||||
| 
 | ||||
| static int debounce_setup(struct line *line, | ||||
| 			  unsigned int debounce_period_us, bool hte_req) | ||||
| static int debounce_setup(struct line *line, unsigned int debounce_period_us) | ||||
| { | ||||
| 	unsigned long irqflags; | ||||
| 	int ret, level, irq; | ||||
|  | @ -864,7 +869,7 @@ static int debounce_setup(struct line *line, | |||
| 		if (level < 0) | ||||
| 			return level; | ||||
| 
 | ||||
| 		if (!hte_req) { | ||||
| 		if (!test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) { | ||||
| 			irq = gpiod_to_irq(line->desc); | ||||
| 			if (irq < 0) | ||||
| 				return -ENXIO; | ||||
|  | @ -915,19 +920,19 @@ static u32 gpio_v2_line_config_debounce_period(struct gpio_v2_line_config *lc, | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void edge_detector_stop(struct line *line, bool hte_en) | ||||
| static void edge_detector_stop(struct line *line) | ||||
| { | ||||
| 	if (line->irq && !hte_en) { | ||||
| 	if (line->irq) { | ||||
| 		free_irq(line->irq, line); | ||||
| 		line->irq = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	if (hte_en) | ||||
| 	if (READ_ONCE(line->edflags) & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) | ||||
| 		hte_ts_put(&line->hdesc); | ||||
| 
 | ||||
| 	cancel_delayed_work_sync(&line->work); | ||||
| 	WRITE_ONCE(line->sw_debounced, 0); | ||||
| 	WRITE_ONCE(line->eflags, 0); | ||||
| 	WRITE_ONCE(line->edflags, 0); | ||||
| 	if (line->desc) | ||||
| 		WRITE_ONCE(line->desc->debounce_period_us, 0); | ||||
| 	/* do not change line->level - see comment in debounced_value() */ | ||||
|  | @ -935,23 +940,23 @@ static void edge_detector_stop(struct line *line, bool hte_en) | |||
| 
 | ||||
| static int edge_detector_setup(struct line *line, | ||||
| 			       struct gpio_v2_line_config *lc, | ||||
| 			       unsigned int line_idx, | ||||
| 			       u64 eflags, bool hte_req) | ||||
| 			       unsigned int line_idx, u64 edflags) | ||||
| { | ||||
| 	u32 debounce_period_us; | ||||
| 	unsigned long irqflags = 0; | ||||
| 	u64 eflags; | ||||
| 	int irq, ret; | ||||
| 
 | ||||
| 	eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS; | ||||
| 	if (eflags && !kfifo_initialized(&line->req->events)) { | ||||
| 		ret = kfifo_alloc(&line->req->events, | ||||
| 				  line->req->event_buffer_size, GFP_KERNEL); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 	WRITE_ONCE(line->eflags, eflags); | ||||
| 	if (gpio_v2_line_config_debounced(lc, line_idx)) { | ||||
| 		debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx); | ||||
| 		ret = debounce_setup(line, debounce_period_us, hte_req); | ||||
| 		ret = debounce_setup(line, debounce_period_us); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 		WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); | ||||
|  | @ -961,8 +966,8 @@ static int edge_detector_setup(struct line *line, | |||
| 	if (!eflags || READ_ONCE(line->sw_debounced)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (hte_req) | ||||
| 		return hte_edge_setup(line, eflags); | ||||
| 	if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) | ||||
| 		return hte_edge_setup(line, edflags); | ||||
| 
 | ||||
| 	irq = gpiod_to_irq(line->desc); | ||||
| 	if (irq < 0) | ||||
|  | @ -988,35 +993,29 @@ static int edge_detector_setup(struct line *line, | |||
| 
 | ||||
| static int edge_detector_update(struct line *line, | ||||
| 				struct gpio_v2_line_config *lc, | ||||
| 				unsigned int line_idx, | ||||
| 				u64 flags, bool polarity_change, | ||||
| 				bool prev_hte_flag) | ||||
| 				unsigned int line_idx, u64 edflags) | ||||
| { | ||||
| 	u64 eflags = flags & GPIO_V2_LINE_EDGE_FLAGS; | ||||
| 	u64 active_edflags = READ_ONCE(line->edflags); | ||||
| 	unsigned int debounce_period_us = | ||||
| 			gpio_v2_line_config_debounce_period(lc, line_idx); | ||||
| 	bool hte_change = (prev_hte_flag != | ||||
| 		      ((flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) != 0)); | ||||
| 
 | ||||
| 	if ((READ_ONCE(line->eflags) == eflags) && !polarity_change && | ||||
| 	    (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us) | ||||
| 	    && !hte_change) | ||||
| 	if ((active_edflags == edflags) && | ||||
| 	    (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* sw debounced and still will be...*/ | ||||
| 	if (debounce_period_us && READ_ONCE(line->sw_debounced)) { | ||||
| 		WRITE_ONCE(line->eflags, eflags); | ||||
| 		WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* reconfiguring edge detection or sw debounce being disabled */ | ||||
| 	if ((line->irq && !READ_ONCE(line->sw_debounced)) || prev_hte_flag || | ||||
| 	if ((line->irq && !READ_ONCE(line->sw_debounced)) || | ||||
| 	    (active_edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) || | ||||
| 	    (!debounce_period_us && READ_ONCE(line->sw_debounced))) | ||||
| 		edge_detector_stop(line, prev_hte_flag); | ||||
| 		edge_detector_stop(line); | ||||
| 
 | ||||
| 	return edge_detector_setup(line, lc, line_idx, eflags, | ||||
| 				   flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE); | ||||
| 	return edge_detector_setup(line, lc, line_idx, edflags); | ||||
| } | ||||
| 
 | ||||
| static u64 gpio_v2_line_config_flags(struct gpio_v2_line_config *lc, | ||||
|  | @ -1285,22 +1284,17 @@ static long linereq_set_config_unlocked(struct linereq *lr, | |||
| 					struct gpio_v2_line_config *lc) | ||||
| { | ||||
| 	struct gpio_desc *desc; | ||||
| 	struct line *line; | ||||
| 	unsigned int i; | ||||
| 	u64 flags; | ||||
| 	bool polarity_change; | ||||
| 	bool prev_hte_flag; | ||||
| 	u64 flags, edflags; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	for (i = 0; i < lr->num_lines; i++) { | ||||
| 		line = &lr->lines[i]; | ||||
| 		desc = lr->lines[i].desc; | ||||
| 		flags = gpio_v2_line_config_flags(lc, i); | ||||
| 		polarity_change = | ||||
| 			(!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) != | ||||
| 			 ((flags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) != 0)); | ||||
| 
 | ||||
| 		prev_hte_flag = !!test_bit(FLAG_EVENT_CLOCK_HTE, &desc->flags); | ||||
| 
 | ||||
| 		gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags); | ||||
| 		edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS; | ||||
| 		/*
 | ||||
| 		 * Lines have to be requested explicitly for input | ||||
| 		 * or output, else the line will be treated "as is". | ||||
|  | @ -1308,7 +1302,7 @@ static long linereq_set_config_unlocked(struct linereq *lr, | |||
| 		if (flags & GPIO_V2_LINE_FLAG_OUTPUT) { | ||||
| 			int val = gpio_v2_line_config_output_value(lc, i); | ||||
| 
 | ||||
| 			edge_detector_stop(&lr->lines[i], prev_hte_flag); | ||||
| 			edge_detector_stop(line); | ||||
| 			ret = gpiod_direction_output(desc, val); | ||||
| 			if (ret) | ||||
| 				return ret; | ||||
|  | @ -1317,12 +1311,13 @@ static long linereq_set_config_unlocked(struct linereq *lr, | |||
| 			if (ret) | ||||
| 				return ret; | ||||
| 
 | ||||
| 			ret = edge_detector_update(&lr->lines[i], lc, i, | ||||
| 					flags, polarity_change, prev_hte_flag); | ||||
| 			ret = edge_detector_update(line, lc, i, edflags); | ||||
| 			if (ret) | ||||
| 				return ret; | ||||
| 		} | ||||
| 
 | ||||
| 		WRITE_ONCE(line->edflags, edflags); | ||||
| 
 | ||||
| 		blocking_notifier_call_chain(&desc->gdev->notifier, | ||||
| 					     GPIO_V2_LINE_CHANGED_CONFIG, | ||||
| 					     desc); | ||||
|  | @ -1449,13 +1444,10 @@ static ssize_t linereq_read(struct file *file, | |||
| static void linereq_free(struct linereq *lr) | ||||
| { | ||||
| 	unsigned int i; | ||||
| 	bool hte; | ||||
| 
 | ||||
| 	for (i = 0; i < lr->num_lines; i++) { | ||||
| 		if (lr->lines[i].desc) { | ||||
| 			hte = !!test_bit(FLAG_EVENT_CLOCK_HTE, | ||||
| 					 &lr->lines[i].desc->flags); | ||||
| 			edge_detector_stop(&lr->lines[i], hte); | ||||
| 			edge_detector_stop(&lr->lines[i]); | ||||
| 			gpiod_free(lr->lines[i].desc); | ||||
| 		} | ||||
| 	} | ||||
|  | @ -1491,7 +1483,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) | |||
| 	struct gpio_v2_line_config *lc; | ||||
| 	struct linereq *lr; | ||||
| 	struct file *file; | ||||
| 	u64 flags; | ||||
| 	u64 flags, edflags; | ||||
| 	unsigned int i; | ||||
| 	int fd, ret; | ||||
| 
 | ||||
|  | @ -1565,6 +1557,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) | |||
| 		if (ret < 0) | ||||
| 			goto out_free_linereq; | ||||
| 
 | ||||
| 		edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS; | ||||
| 		/*
 | ||||
| 		 * Lines have to be requested explicitly for input | ||||
| 		 * or output, else the line will be treated "as is". | ||||
|  | @ -1581,12 +1574,13 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) | |||
| 				goto out_free_linereq; | ||||
| 
 | ||||
| 			ret = edge_detector_setup(&lr->lines[i], lc, i, | ||||
| 				flags & GPIO_V2_LINE_EDGE_FLAGS, | ||||
| 				flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE); | ||||
| 						  edflags); | ||||
| 			if (ret) | ||||
| 				goto out_free_linereq; | ||||
| 		} | ||||
| 
 | ||||
| 		lr->lines[i].edflags = edflags; | ||||
| 
 | ||||
| 		blocking_notifier_call_chain(&desc->gdev->notifier, | ||||
| 					     GPIO_V2_LINE_CHANGED_REQUESTED, desc); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Kent Gibson
						Kent Gibson