Merge tag 'pci-v6.4-fixes-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
[linux.git] / drivers / gpio / gpio-idio-16.c
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");