1 // SPDX-License-Identifier: GPL-2.0-only
3 * GPIO driver for the ACCES 104-DIO-48E series
4 * Copyright (C) 2016 William Breathitt Gray
6 * This driver supports the following ACCES devices: 104-DIO-48E and
9 #include <linux/bits.h>
10 #include <linux/device.h>
11 #include <linux/err.h>
12 #include <linux/i8254.h>
13 #include <linux/ioport.h>
14 #include <linux/irq.h>
15 #include <linux/isa.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/moduleparam.h>
19 #include <linux/regmap.h>
20 #include <linux/spinlock.h>
21 #include <linux/types.h>
23 #include "gpio-i8255.h"
25 MODULE_IMPORT_NS(I8255
);
27 #define DIO48E_EXTENT 16
28 #define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT)
30 static unsigned int base
[MAX_NUM_DIO48E
];
31 static unsigned int num_dio48e
;
32 module_param_hw_array(base
, uint
, ioport
, &num_dio48e
, 0);
33 MODULE_PARM_DESC(base
, "ACCES 104-DIO-48E base addresses");
35 static unsigned int irq
[MAX_NUM_DIO48E
];
36 static unsigned int num_irq
;
37 module_param_hw_array(irq
, uint
, irq
, &num_irq
, 0);
38 MODULE_PARM_DESC(irq
, "ACCES 104-DIO-48E interrupt line numbers");
40 #define DIO48E_ENABLE_INTERRUPT 0xB
41 #define DIO48E_DISABLE_INTERRUPT DIO48E_ENABLE_INTERRUPT
42 #define DIO48E_ENABLE_COUNTER_TIMER_ADDRESSING 0xD
43 #define DIO48E_DISABLE_COUNTER_TIMER_ADDRESSING DIO48E_ENABLE_COUNTER_TIMER_ADDRESSING
44 #define DIO48E_CLEAR_INTERRUPT 0xF
46 #define DIO48E_NUM_PPI 2
48 static const struct regmap_range dio48e_wr_ranges
[] = {
49 regmap_reg_range(0x0, 0x9), regmap_reg_range(0xB, 0xB),
50 regmap_reg_range(0xD, 0xD), regmap_reg_range(0xF, 0xF),
52 static const struct regmap_range dio48e_rd_ranges
[] = {
53 regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x6),
54 regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
55 regmap_reg_range(0xF, 0xF),
57 static const struct regmap_range dio48e_volatile_ranges
[] = {
58 i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4),
59 regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
60 regmap_reg_range(0xF, 0xF),
62 static const struct regmap_range dio48e_precious_ranges
[] = {
63 regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
64 regmap_reg_range(0xF, 0xF),
66 static const struct regmap_access_table dio48e_wr_table
= {
67 .yes_ranges
= dio48e_wr_ranges
,
68 .n_yes_ranges
= ARRAY_SIZE(dio48e_wr_ranges
),
70 static const struct regmap_access_table dio48e_rd_table
= {
71 .yes_ranges
= dio48e_rd_ranges
,
72 .n_yes_ranges
= ARRAY_SIZE(dio48e_rd_ranges
),
74 static const struct regmap_access_table dio48e_volatile_table
= {
75 .yes_ranges
= dio48e_volatile_ranges
,
76 .n_yes_ranges
= ARRAY_SIZE(dio48e_volatile_ranges
),
78 static const struct regmap_access_table dio48e_precious_table
= {
79 .yes_ranges
= dio48e_precious_ranges
,
80 .n_yes_ranges
= ARRAY_SIZE(dio48e_precious_ranges
),
83 static const struct regmap_range pit_wr_ranges
[] = {
84 regmap_reg_range(0x0, 0x3),
86 static const struct regmap_range pit_rd_ranges
[] = {
87 regmap_reg_range(0x0, 0x2),
89 static const struct regmap_access_table pit_wr_table
= {
90 .yes_ranges
= pit_wr_ranges
,
91 .n_yes_ranges
= ARRAY_SIZE(pit_wr_ranges
),
93 static const struct regmap_access_table pit_rd_table
= {
94 .yes_ranges
= pit_rd_ranges
,
95 .n_yes_ranges
= ARRAY_SIZE(pit_rd_ranges
),
98 /* only bit 3 on each respective Port C supports interrupts */
99 #define DIO48E_REGMAP_IRQ(_ppi) \
100 [19 + (_ppi) * 24] = { \
102 .type = { .types_supported = IRQ_TYPE_EDGE_RISING }, \
105 static const struct regmap_irq dio48e_regmap_irqs
[] = {
106 DIO48E_REGMAP_IRQ(0), DIO48E_REGMAP_IRQ(1),
110 * struct dio48e_gpio - GPIO device private data structure
111 * @lock: synchronization lock to prevent I/O race conditions
112 * @map: Regmap for the device
113 * @regs: virtual mapping for device registers
114 * @flags: IRQ flags saved during locking
115 * @irq_mask: Current IRQ mask state on the device
122 unsigned int irq_mask
;
125 static void dio48e_regmap_lock(void *lock_arg
) __acquires(&dio48egpio
->lock
)
127 struct dio48e_gpio
*const dio48egpio
= lock_arg
;
130 raw_spin_lock_irqsave(&dio48egpio
->lock
, flags
);
131 dio48egpio
->flags
= flags
;
134 static void dio48e_regmap_unlock(void *lock_arg
) __releases(&dio48egpio
->lock
)
136 struct dio48e_gpio
*const dio48egpio
= lock_arg
;
138 raw_spin_unlock_irqrestore(&dio48egpio
->lock
, dio48egpio
->flags
);
141 static void pit_regmap_lock(void *lock_arg
) __acquires(&dio48egpio
->lock
)
143 struct dio48e_gpio
*const dio48egpio
= lock_arg
;
146 raw_spin_lock_irqsave(&dio48egpio
->lock
, flags
);
147 dio48egpio
->flags
= flags
;
149 iowrite8(0x00, dio48egpio
->regs
+ DIO48E_ENABLE_COUNTER_TIMER_ADDRESSING
);
152 static void pit_regmap_unlock(void *lock_arg
) __releases(&dio48egpio
->lock
)
154 struct dio48e_gpio
*const dio48egpio
= lock_arg
;
156 ioread8(dio48egpio
->regs
+ DIO48E_DISABLE_COUNTER_TIMER_ADDRESSING
);
158 raw_spin_unlock_irqrestore(&dio48egpio
->lock
, dio48egpio
->flags
);
161 static int dio48e_handle_mask_sync(const int index
,
162 const unsigned int mask_buf_def
,
163 const unsigned int mask_buf
,
164 void *const irq_drv_data
)
166 struct dio48e_gpio
*const dio48egpio
= irq_drv_data
;
167 const unsigned int prev_mask
= dio48egpio
->irq_mask
;
171 /* exit early if no change since the previous mask */
172 if (mask_buf
== prev_mask
)
175 /* remember the current mask for the next mask sync */
176 dio48egpio
->irq_mask
= mask_buf
;
178 /* if all previously masked, enable interrupts when unmasking */
179 if (prev_mask
== mask_buf_def
) {
180 err
= regmap_write(dio48egpio
->map
, DIO48E_CLEAR_INTERRUPT
, 0x00);
183 return regmap_write(dio48egpio
->map
, DIO48E_ENABLE_INTERRUPT
, 0x00);
186 /* if all are currently masked, disable interrupts */
187 if (mask_buf
== mask_buf_def
)
188 return regmap_read(dio48egpio
->map
, DIO48E_DISABLE_INTERRUPT
, &val
);
193 #define DIO48E_NGPIO 48
194 static const char *dio48e_names
[DIO48E_NGPIO
] = {
195 "PPI Group 0 Port A 0", "PPI Group 0 Port A 1", "PPI Group 0 Port A 2",
196 "PPI Group 0 Port A 3", "PPI Group 0 Port A 4", "PPI Group 0 Port A 5",
197 "PPI Group 0 Port A 6", "PPI Group 0 Port A 7", "PPI Group 0 Port B 0",
198 "PPI Group 0 Port B 1", "PPI Group 0 Port B 2", "PPI Group 0 Port B 3",
199 "PPI Group 0 Port B 4", "PPI Group 0 Port B 5", "PPI Group 0 Port B 6",
200 "PPI Group 0 Port B 7", "PPI Group 0 Port C 0", "PPI Group 0 Port C 1",
201 "PPI Group 0 Port C 2", "PPI Group 0 Port C 3", "PPI Group 0 Port C 4",
202 "PPI Group 0 Port C 5", "PPI Group 0 Port C 6", "PPI Group 0 Port C 7",
203 "PPI Group 1 Port A 0", "PPI Group 1 Port A 1", "PPI Group 1 Port A 2",
204 "PPI Group 1 Port A 3", "PPI Group 1 Port A 4", "PPI Group 1 Port A 5",
205 "PPI Group 1 Port A 6", "PPI Group 1 Port A 7", "PPI Group 1 Port B 0",
206 "PPI Group 1 Port B 1", "PPI Group 1 Port B 2", "PPI Group 1 Port B 3",
207 "PPI Group 1 Port B 4", "PPI Group 1 Port B 5", "PPI Group 1 Port B 6",
208 "PPI Group 1 Port B 7", "PPI Group 1 Port C 0", "PPI Group 1 Port C 1",
209 "PPI Group 1 Port C 2", "PPI Group 1 Port C 3", "PPI Group 1 Port C 4",
210 "PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7"
213 static int dio48e_irq_init_hw(struct regmap
*const map
)
217 /* Disable IRQ by default */
218 return regmap_read(map
, DIO48E_DISABLE_INTERRUPT
, &val
);
221 static int dio48e_probe(struct device
*dev
, unsigned int id
)
223 const char *const name
= dev_name(dev
);
224 struct i8255_regmap_config config
= {};
227 struct regmap_config dio48e_regmap_config
;
228 struct regmap_config pit_regmap_config
;
229 struct i8254_regmap_config pit_config
;
231 struct regmap_irq_chip
*chip
;
232 struct dio48e_gpio
*dio48egpio
;
233 struct regmap_irq_chip_data
*chip_data
;
235 if (!devm_request_region(dev
, base
[id
], DIO48E_EXTENT
, name
)) {
236 dev_err(dev
, "Unable to lock port addresses (0x%X-0x%X)\n",
237 base
[id
], base
[id
] + DIO48E_EXTENT
);
241 dio48egpio
= devm_kzalloc(dev
, sizeof(*dio48egpio
), GFP_KERNEL
);
245 regs
= devm_ioport_map(dev
, base
[id
], DIO48E_EXTENT
);
249 dio48egpio
->regs
= regs
;
251 raw_spin_lock_init(&dio48egpio
->lock
);
253 dio48e_regmap_config
= (struct regmap_config
) {
257 .lock
= dio48e_regmap_lock
,
258 .unlock
= dio48e_regmap_unlock
,
259 .lock_arg
= dio48egpio
,
261 .wr_table
= &dio48e_wr_table
,
262 .rd_table
= &dio48e_rd_table
,
263 .volatile_table
= &dio48e_volatile_table
,
264 .precious_table
= &dio48e_precious_table
,
265 .cache_type
= REGCACHE_FLAT
,
268 map
= devm_regmap_init_mmio(dev
, regs
, &dio48e_regmap_config
);
270 return dev_err_probe(dev
, PTR_ERR(map
),
271 "Unable to initialize register map\n");
273 dio48egpio
->map
= map
;
275 pit_regmap_config
= (struct regmap_config
) {
280 .lock
= pit_regmap_lock
,
281 .unlock
= pit_regmap_unlock
,
282 .lock_arg
= dio48egpio
,
284 .wr_table
= &pit_wr_table
,
285 .rd_table
= &pit_rd_table
,
288 pit_config
.map
= devm_regmap_init_mmio(dev
, regs
, &pit_regmap_config
);
289 if (IS_ERR(pit_config
.map
))
290 return dev_err_probe(dev
, PTR_ERR(pit_config
.map
),
291 "Unable to initialize i8254 register map\n");
293 chip
= devm_kzalloc(dev
, sizeof(*chip
), GFP_KERNEL
);
298 chip
->mask_base
= DIO48E_ENABLE_INTERRUPT
;
299 chip
->ack_base
= DIO48E_CLEAR_INTERRUPT
;
300 chip
->no_status
= true;
302 chip
->irqs
= dio48e_regmap_irqs
;
303 chip
->num_irqs
= ARRAY_SIZE(dio48e_regmap_irqs
);
304 chip
->handle_mask_sync
= dio48e_handle_mask_sync
;
305 chip
->irq_drv_data
= dio48egpio
;
307 /* Initialize to prevent spurious interrupts before we're ready */
308 err
= dio48e_irq_init_hw(map
);
312 err
= devm_regmap_add_irq_chip(dev
, map
, irq
[id
], 0, 0, chip
, &chip_data
);
314 return dev_err_probe(dev
, err
, "IRQ registration failed\n");
316 pit_config
.parent
= dev
;
318 err
= devm_i8254_regmap_register(dev
, &pit_config
);
324 config
.num_ppi
= DIO48E_NUM_PPI
;
325 config
.names
= dio48e_names
;
326 config
.domain
= regmap_irq_get_domain(chip_data
);
328 return devm_i8255_regmap_register(dev
, &config
);
331 static struct isa_driver dio48e_driver
= {
332 .probe
= dio48e_probe
,
334 .name
= "104-dio-48e"
337 module_isa_driver_with_irq(dio48e_driver
, num_dio48e
, num_irq
);
339 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
340 MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver");
341 MODULE_LICENSE("GPL v2");
342 MODULE_IMPORT_NS(I8254
);