xref: /linux/drivers/gpio/gpio-idio-16.c (revision 9f2c9170934eace462499ba0bfe042cc72900173)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * GPIO library for the ACCES IDIO-16 family
4  * Copyright (C) 2022 William Breathitt Gray
5  */
6 #include <linux/bitmap.h>
7 #include <linux/export.h>
8 #include <linux/io.h>
9 #include <linux/module.h>
10 #include <linux/spinlock.h>
11 #include <linux/types.h>
12 
13 #include "gpio-idio-16.h"
14 
15 #define DEFAULT_SYMBOL_NAMESPACE GPIO_IDIO_16
16 
17 /**
18  * idio_16_get - get signal value at signal offset
19  * @reg:	ACCES IDIO-16 device registers
20  * @state:	ACCES IDIO-16 device state
21  * @offset:	offset of signal to get
22  *
23  * Returns the signal value (0=low, 1=high) for the signal at @offset.
24  */
25 int idio_16_get(struct idio_16 __iomem *const reg,
26 		struct idio_16_state *const state, const unsigned long offset)
27 {
28 	const unsigned long mask = BIT(offset);
29 
30 	if (offset < IDIO_16_NOUT)
31 		return test_bit(offset, state->out_state);
32 
33 	if (offset < 24)
34 		return !!(ioread8(&reg->in0_7) & (mask >> IDIO_16_NOUT));
35 
36 	if (offset < 32)
37 		return !!(ioread8(&reg->in8_15) & (mask >> 24));
38 
39 	return -EINVAL;
40 }
41 EXPORT_SYMBOL_GPL(idio_16_get);
42 
43 /**
44  * idio_16_get_multiple - get multiple signal values at multiple signal offsets
45  * @reg:	ACCES IDIO-16 device registers
46  * @state:	ACCES IDIO-16 device state
47  * @mask:	mask of signals to get
48  * @bits:	bitmap to store signal values
49  *
50  * Stores in @bits the values (0=low, 1=high) for the signals defined by @mask.
51  */
52 void idio_16_get_multiple(struct idio_16 __iomem *const reg,
53 			  struct idio_16_state *const state,
54 			  const unsigned long *const mask,
55 			  unsigned long *const bits)
56 {
57 	unsigned long flags;
58 	const unsigned long out_mask = GENMASK(IDIO_16_NOUT - 1, 0);
59 
60 	spin_lock_irqsave(&state->lock, flags);
61 
62 	bitmap_replace(bits, bits, state->out_state, &out_mask, IDIO_16_NOUT);
63 	if (*mask & GENMASK(23, 16))
64 		bitmap_set_value8(bits, ioread8(&reg->in0_7), 16);
65 	if (*mask & GENMASK(31, 24))
66 		bitmap_set_value8(bits, ioread8(&reg->in8_15), 24);
67 
68 	spin_unlock_irqrestore(&state->lock, flags);
69 }
70 EXPORT_SYMBOL_GPL(idio_16_get_multiple);
71 
72 /**
73  * idio_16_set - set signal value at signal offset
74  * @reg:	ACCES IDIO-16 device registers
75  * @state:	ACCES IDIO-16 device state
76  * @offset:	offset of signal to set
77  * @value:	value of signal to set
78  *
79  * Assigns output @value for the signal at @offset.
80  */
81 void idio_16_set(struct idio_16 __iomem *const reg,
82 		 struct idio_16_state *const state, const unsigned long offset,
83 		 const unsigned long value)
84 {
85 	unsigned long flags;
86 
87 	if (offset >= IDIO_16_NOUT)
88 		return;
89 
90 	spin_lock_irqsave(&state->lock, flags);
91 
92 	__assign_bit(offset, state->out_state, value);
93 	if (offset < 8)
94 		iowrite8(bitmap_get_value8(state->out_state, 0), &reg->out0_7);
95 	else
96 		iowrite8(bitmap_get_value8(state->out_state, 8), &reg->out8_15);
97 
98 	spin_unlock_irqrestore(&state->lock, flags);
99 }
100 EXPORT_SYMBOL_GPL(idio_16_set);
101 
102 /**
103  * idio_16_set_multiple - set signal values at multiple signal offsets
104  * @reg:	ACCES IDIO-16 device registers
105  * @state:	ACCES IDIO-16 device state
106  * @mask:	mask of signals to set
107  * @bits:	bitmap of signal output values
108  *
109  * Assigns output values defined by @bits for the signals defined by @mask.
110  */
111 void idio_16_set_multiple(struct idio_16 __iomem *const reg,
112 			  struct idio_16_state *const state,
113 			  const unsigned long *const mask,
114 			  const unsigned long *const bits)
115 {
116 	unsigned long flags;
117 
118 	spin_lock_irqsave(&state->lock, flags);
119 
120 	bitmap_replace(state->out_state, state->out_state, bits, mask,
121 		       IDIO_16_NOUT);
122 	if (*mask & GENMASK(7, 0))
123 		iowrite8(bitmap_get_value8(state->out_state, 0), &reg->out0_7);
124 	if (*mask & GENMASK(15, 8))
125 		iowrite8(bitmap_get_value8(state->out_state, 8), &reg->out8_15);
126 
127 	spin_unlock_irqrestore(&state->lock, flags);
128 }
129 EXPORT_SYMBOL_GPL(idio_16_set_multiple);
130 
131 /**
132  * idio_16_state_init - initialize idio_16_state structure
133  * @state:	ACCES IDIO-16 device state
134  *
135  * Initializes the ACCES IDIO-16 device @state for use in idio-16 library
136  * functions.
137  */
138 void idio_16_state_init(struct idio_16_state *const state)
139 {
140 	spin_lock_init(&state->lock);
141 }
142 EXPORT_SYMBOL_GPL(idio_16_state_init);
143 
144 MODULE_AUTHOR("William Breathitt Gray");
145 MODULE_DESCRIPTION("ACCES IDIO-16 GPIO Library");
146 MODULE_LICENSE("GPL");
147