forked from mirrors/linux
		
	gpio: idio-16: Introduce the ACCES IDIO-16 GPIO library module
Exposes consumer library functions to facilitate communication with devices within the ACCES IDIO-16 family such as the 104-IDIO-16 and the PCI-IDIO-16. A CONFIG_GPIO_IDIO_16 Kconfig option is introduced by this patch. Modules wanting access to these idio-16 library functions should select this Kconfig option and import the GPIO_IDIO_16 symbol namespace. Cc: Andy Shevchenko <andriy.shevchenko@intel.com> Signed-off-by: William Breathitt Gray <william.gray@linaro.org> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
This commit is contained in:
		
							parent
							
								
									6de0cb80e6
								
							
						
					
					
						commit
						b9b1fc1ae1
					
				
					 5 changed files with 234 additions and 0 deletions
				
			
		|  | @ -312,6 +312,13 @@ L:	linux-iio@vger.kernel.org | |||
| S:	Maintained | ||||
| F:	drivers/counter/104-quad-8.c | ||||
| 
 | ||||
| ACCES IDIO-16 GPIO LIBRARY | ||||
| M:	William Breathitt Gray <william.gray@linaro.org> | ||||
| L:	linux-gpio@vger.kernel.org | ||||
| S:	Maintained | ||||
| F:	drivers/gpio/gpio-idio-16.c | ||||
| F:	drivers/gpio/gpio-idio-16.h | ||||
| 
 | ||||
| ACCES PCI-IDIO-16 GPIO DRIVER | ||||
| M:	William Breathitt Gray <william.gray@linaro.org> | ||||
| L:	linux-gpio@vger.kernel.org | ||||
|  |  | |||
|  | @ -109,6 +109,15 @@ config GPIO_REGMAP | |||
| config GPIO_MAX730X | ||||
| 	tristate | ||||
| 
 | ||||
| config GPIO_IDIO_16 | ||||
| 	tristate | ||||
| 	help | ||||
| 	  Enables support for the idio-16 library functions. The idio-16 library | ||||
| 	  provides functions to facilitate communication with devices within the | ||||
| 	  ACCES IDIO-16 family such as the 104-IDIO-16 and the PCI-IDIO-16. | ||||
| 
 | ||||
| 	  If built as a module its name will be gpio-idio-16. | ||||
| 
 | ||||
| menu "Memory mapped GPIO drivers" | ||||
| 	depends on HAS_IOMEM | ||||
| 
 | ||||
|  |  | |||
|  | @ -68,6 +68,7 @@ obj-$(CONFIG_GPIO_HLWD)			+= gpio-hlwd.o | |||
| obj-$(CONFIG_HTC_EGPIO)			+= gpio-htc-egpio.o | ||||
| obj-$(CONFIG_GPIO_I8255)		+= gpio-i8255.o | ||||
| obj-$(CONFIG_GPIO_ICH)			+= gpio-ich.o | ||||
| obj-$(CONFIG_GPIO_IDIO_16)		+= gpio-idio-16.o | ||||
| obj-$(CONFIG_GPIO_IDT3243X)		+= gpio-idt3243x.o | ||||
| obj-$(CONFIG_GPIO_IMX_SCU)		+= gpio-imx-scu.o | ||||
| obj-$(CONFIG_GPIO_IOP)			+= gpio-iop.o | ||||
|  |  | |||
							
								
								
									
										146
									
								
								drivers/gpio/gpio-idio-16.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								drivers/gpio/gpio-idio-16.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,146 @@ | |||
| // SPDX-License-Identifier: GPL-2.0
 | ||||
| /*
 | ||||
|  * GPIO library for the ACCES IDIO-16 family | ||||
|  * Copyright (C) 2022 William Breathitt Gray | ||||
|  */ | ||||
| #include <linux/bitmap.h> | ||||
| #include <linux/export.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/spinlock.h> | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| #include "gpio-idio-16.h" | ||||
| 
 | ||||
| #define DEFAULT_SYMBOL_NAMESPACE GPIO_IDIO_16 | ||||
| 
 | ||||
| /**
 | ||||
|  * idio_16_get - get signal value at signal offset | ||||
|  * @reg:	ACCES IDIO-16 device registers | ||||
|  * @state:	ACCES IDIO-16 device state | ||||
|  * @offset:	offset of signal to get | ||||
|  * | ||||
|  * Returns the signal value (0=low, 1=high) for the signal at @offset. | ||||
|  */ | ||||
| int idio_16_get(struct idio_16 __iomem *const reg, | ||||
| 		struct idio_16_state *const state, const unsigned long offset) | ||||
| { | ||||
| 	const unsigned long mask = BIT(offset); | ||||
| 
 | ||||
| 	if (offset < IDIO_16_NOUT) | ||||
| 		return test_bit(offset, state->out_state); | ||||
| 
 | ||||
| 	if (offset < 24) | ||||
| 		return !!(ioread8(®->in0_7) & (mask >> IDIO_16_NOUT)); | ||||
| 
 | ||||
| 	if (offset < 32) | ||||
| 		return !!(ioread8(®->in8_15) & (mask >> 24)); | ||||
| 
 | ||||
| 	return -EINVAL; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(idio_16_get); | ||||
| 
 | ||||
| /**
 | ||||
|  * idio_16_get_multiple - get multiple signal values at multiple signal offsets | ||||
|  * @reg:	ACCES IDIO-16 device registers | ||||
|  * @state:	ACCES IDIO-16 device state | ||||
|  * @mask:	mask of signals to get | ||||
|  * @bits:	bitmap to store signal values | ||||
|  * | ||||
|  * Stores in @bits the values (0=low, 1=high) for the signals defined by @mask. | ||||
|  */ | ||||
| void idio_16_get_multiple(struct idio_16 __iomem *const reg, | ||||
| 			  struct idio_16_state *const state, | ||||
| 			  const unsigned long *const mask, | ||||
| 			  unsigned long *const bits) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	const unsigned long out_mask = GENMASK(IDIO_16_NOUT - 1, 0); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&state->lock, flags); | ||||
| 
 | ||||
| 	bitmap_replace(bits, bits, state->out_state, &out_mask, IDIO_16_NOUT); | ||||
| 	if (*mask & GENMASK(23, 16)) | ||||
| 		bitmap_set_value8(bits, ioread8(®->in0_7), 16); | ||||
| 	if (*mask & GENMASK(31, 24)) | ||||
| 		bitmap_set_value8(bits, ioread8(®->in8_15), 24); | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&state->lock, flags); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(idio_16_get_multiple); | ||||
| 
 | ||||
| /**
 | ||||
|  * idio_16_set - set signal value at signal offset | ||||
|  * @reg:	ACCES IDIO-16 device registers | ||||
|  * @state:	ACCES IDIO-16 device state | ||||
|  * @offset:	offset of signal to set | ||||
|  * @value:	value of signal to set | ||||
|  * | ||||
|  * Assigns output @value for the signal at @offset. | ||||
|  */ | ||||
| void idio_16_set(struct idio_16 __iomem *const reg, | ||||
| 		 struct idio_16_state *const state, const unsigned long offset, | ||||
| 		 const unsigned long value) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	if (offset >= IDIO_16_NOUT) | ||||
| 		return; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&state->lock, flags); | ||||
| 
 | ||||
| 	__assign_bit(offset, state->out_state, value); | ||||
| 	if (offset < 8) | ||||
| 		iowrite8(bitmap_get_value8(state->out_state, 0), ®->out0_7); | ||||
| 	else | ||||
| 		iowrite8(bitmap_get_value8(state->out_state, 8), ®->out8_15); | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&state->lock, flags); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(idio_16_set); | ||||
| 
 | ||||
| /**
 | ||||
|  * idio_16_set_multiple - set signal values at multiple signal offsets | ||||
|  * @reg:	ACCES IDIO-16 device registers | ||||
|  * @state:	ACCES IDIO-16 device state | ||||
|  * @mask:	mask of signals to set | ||||
|  * @bits:	bitmap of signal output values | ||||
|  * | ||||
|  * Assigns output values defined by @bits for the signals defined by @mask. | ||||
|  */ | ||||
| void idio_16_set_multiple(struct idio_16 __iomem *const reg, | ||||
| 			  struct idio_16_state *const state, | ||||
| 			  const unsigned long *const mask, | ||||
| 			  const unsigned long *const bits) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&state->lock, flags); | ||||
| 
 | ||||
| 	bitmap_replace(state->out_state, state->out_state, bits, mask, | ||||
| 		       IDIO_16_NOUT); | ||||
| 	if (*mask & GENMASK(7, 0)) | ||||
| 		iowrite8(bitmap_get_value8(state->out_state, 0), ®->out0_7); | ||||
| 	if (*mask & GENMASK(15, 8)) | ||||
| 		iowrite8(bitmap_get_value8(state->out_state, 8), ®->out8_15); | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&state->lock, flags); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(idio_16_set_multiple); | ||||
| 
 | ||||
| /**
 | ||||
|  * idio_16_state_init - initialize idio_16_state structure | ||||
|  * @state:	ACCES IDIO-16 device state | ||||
|  * | ||||
|  * Initializes the ACCES IDIO-16 device @state for use in idio-16 library | ||||
|  * functions. | ||||
|  */ | ||||
| void idio_16_state_init(struct idio_16_state *const state) | ||||
| { | ||||
| 	spin_lock_init(&state->lock); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(idio_16_state_init); | ||||
| 
 | ||||
| MODULE_AUTHOR("William Breathitt Gray"); | ||||
| MODULE_DESCRIPTION("ACCES IDIO-16 GPIO Library"); | ||||
| MODULE_LICENSE("GPL"); | ||||
							
								
								
									
										71
									
								
								drivers/gpio/gpio-idio-16.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								drivers/gpio/gpio-idio-16.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| /* SPDX-License-Identifier: GPL-2.0 */ | ||||
| /* Copyright 2022 William Breathitt Gray */ | ||||
| #ifndef _IDIO_16_H_ | ||||
| #define _IDIO_16_H_ | ||||
| 
 | ||||
| #include <linux/spinlock.h> | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * struct idio_16 - IDIO-16 registers structure | ||||
|  * @out0_7:	Read: FET Drive Outputs 0-7 | ||||
|  *		Write: FET Drive Outputs 0-7 | ||||
|  * @in0_7:	Read: Isolated Inputs 0-7 | ||||
|  *		Write: Clear Interrupt | ||||
|  * @irq_ctl:	Read: Enable IRQ | ||||
|  *		Write: Disable IRQ | ||||
|  * @filter_ctl:	Read: Activate Input Filters 0-15 | ||||
|  *		Write: Deactivate Input Filters 0-15 | ||||
|  * @out8_15:	Read: FET Drive Outputs 8-15 | ||||
|  *		Write: FET Drive Outputs 8-15 | ||||
|  * @in8_15:	Read: Isolated Inputs 8-15 | ||||
|  *		Write: Unused | ||||
|  * @irq_status:	Read: Interrupt status | ||||
|  *		Write: Unused | ||||
|  */ | ||||
| struct idio_16 { | ||||
| 	u8 out0_7; | ||||
| 	u8 in0_7; | ||||
| 	u8 irq_ctl; | ||||
| 	u8 filter_ctl; | ||||
| 	u8 out8_15; | ||||
| 	u8 in8_15; | ||||
| 	u8 irq_status; | ||||
| }; | ||||
| 
 | ||||
| #define IDIO_16_NOUT 16 | ||||
| 
 | ||||
| /**
 | ||||
|  * struct idio_16_state - IDIO-16 state structure | ||||
|  * @lock:	synchronization lock for accessing device state | ||||
|  * @out_state:	output signals state | ||||
|  */ | ||||
| struct idio_16_state { | ||||
| 	spinlock_t lock; | ||||
| 	DECLARE_BITMAP(out_state, IDIO_16_NOUT); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * idio_16_get_direction - get the I/O direction for a signal offset | ||||
|  * @offset:	offset of signal to get direction | ||||
|  * | ||||
|  * Returns the signal direction (0=output, 1=input) for the signal at @offset. | ||||
|  */ | ||||
| static inline int idio_16_get_direction(const unsigned long offset) | ||||
| { | ||||
| 	return (offset >= IDIO_16_NOUT) ? 1 : 0; | ||||
| } | ||||
| 
 | ||||
| int idio_16_get(struct idio_16 __iomem *reg, struct idio_16_state *state, | ||||
| 		unsigned long offset); | ||||
| void idio_16_get_multiple(struct idio_16 __iomem *reg, | ||||
| 			  struct idio_16_state *state, | ||||
| 			  const unsigned long *mask, unsigned long *bits); | ||||
| void idio_16_set(struct idio_16 __iomem *reg, struct idio_16_state *state, | ||||
| 		 unsigned long offset, unsigned long value); | ||||
| void idio_16_set_multiple(struct idio_16 __iomem *reg, | ||||
| 			  struct idio_16_state *state, | ||||
| 			  const unsigned long *mask, const unsigned long *bits); | ||||
| void idio_16_state_init(struct idio_16_state *state); | ||||
| 
 | ||||
| #endif /* _IDIO_16_H_ */ | ||||
		Loading…
	
		Reference in a new issue
	
	 William Breathitt Gray
						William Breathitt Gray