162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * GPIO driver for the ACCES 104-DIO-48E series
462306a36Sopenharmony_ci * Copyright (C) 2016 William Breathitt Gray
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This driver supports the following ACCES devices: 104-DIO-48E and
762306a36Sopenharmony_ci * 104-DIO-24E.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/bits.h>
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/i8254.h>
1362306a36Sopenharmony_ci#include <linux/ioport.h>
1462306a36Sopenharmony_ci#include <linux/irq.h>
1562306a36Sopenharmony_ci#include <linux/isa.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/moduleparam.h>
1962306a36Sopenharmony_ci#include <linux/regmap.h>
2062306a36Sopenharmony_ci#include <linux/spinlock.h>
2162306a36Sopenharmony_ci#include <linux/types.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "gpio-i8255.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ciMODULE_IMPORT_NS(I8255);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define DIO48E_EXTENT 16
2862306a36Sopenharmony_ci#define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic unsigned int base[MAX_NUM_DIO48E];
3162306a36Sopenharmony_cistatic unsigned int num_dio48e;
3262306a36Sopenharmony_cimodule_param_hw_array(base, uint, ioport, &num_dio48e, 0);
3362306a36Sopenharmony_ciMODULE_PARM_DESC(base, "ACCES 104-DIO-48E base addresses");
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic unsigned int irq[MAX_NUM_DIO48E];
3662306a36Sopenharmony_cistatic unsigned int num_irq;
3762306a36Sopenharmony_cimodule_param_hw_array(irq, uint, irq, &num_irq, 0);
3862306a36Sopenharmony_ciMODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define DIO48E_ENABLE_INTERRUPT 0xB
4162306a36Sopenharmony_ci#define DIO48E_DISABLE_INTERRUPT DIO48E_ENABLE_INTERRUPT
4262306a36Sopenharmony_ci#define DIO48E_ENABLE_COUNTER_TIMER_ADDRESSING 0xD
4362306a36Sopenharmony_ci#define DIO48E_DISABLE_COUNTER_TIMER_ADDRESSING DIO48E_ENABLE_COUNTER_TIMER_ADDRESSING
4462306a36Sopenharmony_ci#define DIO48E_CLEAR_INTERRUPT 0xF
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define DIO48E_NUM_PPI 2
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic const struct regmap_range dio48e_wr_ranges[] = {
4962306a36Sopenharmony_ci	regmap_reg_range(0x0, 0x9), regmap_reg_range(0xB, 0xB),
5062306a36Sopenharmony_ci	regmap_reg_range(0xD, 0xD), regmap_reg_range(0xF, 0xF),
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_cistatic const struct regmap_range dio48e_rd_ranges[] = {
5362306a36Sopenharmony_ci	regmap_reg_range(0x0, 0x2), regmap_reg_range(0x4, 0x6),
5462306a36Sopenharmony_ci	regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
5562306a36Sopenharmony_ci	regmap_reg_range(0xF, 0xF),
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_cistatic const struct regmap_range dio48e_volatile_ranges[] = {
5862306a36Sopenharmony_ci	i8255_volatile_regmap_range(0x0), i8255_volatile_regmap_range(0x4),
5962306a36Sopenharmony_ci	regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
6062306a36Sopenharmony_ci	regmap_reg_range(0xF, 0xF),
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_cistatic const struct regmap_range dio48e_precious_ranges[] = {
6362306a36Sopenharmony_ci	regmap_reg_range(0xB, 0xB), regmap_reg_range(0xD, 0xD),
6462306a36Sopenharmony_ci	regmap_reg_range(0xF, 0xF),
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_cistatic const struct regmap_access_table dio48e_wr_table = {
6762306a36Sopenharmony_ci	.yes_ranges = dio48e_wr_ranges,
6862306a36Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(dio48e_wr_ranges),
6962306a36Sopenharmony_ci};
7062306a36Sopenharmony_cistatic const struct regmap_access_table dio48e_rd_table = {
7162306a36Sopenharmony_ci	.yes_ranges = dio48e_rd_ranges,
7262306a36Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(dio48e_rd_ranges),
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_cistatic const struct regmap_access_table dio48e_volatile_table = {
7562306a36Sopenharmony_ci	.yes_ranges = dio48e_volatile_ranges,
7662306a36Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(dio48e_volatile_ranges),
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_cistatic const struct regmap_access_table dio48e_precious_table = {
7962306a36Sopenharmony_ci	.yes_ranges = dio48e_precious_ranges,
8062306a36Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(dio48e_precious_ranges),
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic const struct regmap_range pit_wr_ranges[] = {
8462306a36Sopenharmony_ci	regmap_reg_range(0x0, 0x3),
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_cistatic const struct regmap_range pit_rd_ranges[] = {
8762306a36Sopenharmony_ci	regmap_reg_range(0x0, 0x2),
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_cistatic const struct regmap_access_table pit_wr_table = {
9062306a36Sopenharmony_ci	.yes_ranges = pit_wr_ranges,
9162306a36Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(pit_wr_ranges),
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_cistatic const struct regmap_access_table pit_rd_table = {
9462306a36Sopenharmony_ci	.yes_ranges = pit_rd_ranges,
9562306a36Sopenharmony_ci	.n_yes_ranges = ARRAY_SIZE(pit_rd_ranges),
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/* only bit 3 on each respective Port C supports interrupts */
9962306a36Sopenharmony_ci#define DIO48E_REGMAP_IRQ(_ppi)						\
10062306a36Sopenharmony_ci	[19 + (_ppi) * 24] = {						\
10162306a36Sopenharmony_ci		.mask = BIT(_ppi),					\
10262306a36Sopenharmony_ci		.type = { .types_supported = IRQ_TYPE_EDGE_RISING },	\
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic const struct regmap_irq dio48e_regmap_irqs[] = {
10662306a36Sopenharmony_ci	DIO48E_REGMAP_IRQ(0), DIO48E_REGMAP_IRQ(1),
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/**
11062306a36Sopenharmony_ci * struct dio48e_gpio - GPIO device private data structure
11162306a36Sopenharmony_ci * @lock:	synchronization lock to prevent I/O race conditions
11262306a36Sopenharmony_ci * @map:	Regmap for the device
11362306a36Sopenharmony_ci * @regs:	virtual mapping for device registers
11462306a36Sopenharmony_ci * @flags:	IRQ flags saved during locking
11562306a36Sopenharmony_ci * @irq_mask:	Current IRQ mask state on the device
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_cistruct dio48e_gpio {
11862306a36Sopenharmony_ci	raw_spinlock_t lock;
11962306a36Sopenharmony_ci	struct regmap *map;
12062306a36Sopenharmony_ci	void __iomem *regs;
12162306a36Sopenharmony_ci	unsigned long flags;
12262306a36Sopenharmony_ci	unsigned int irq_mask;
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic void dio48e_regmap_lock(void *lock_arg) __acquires(&dio48egpio->lock)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct dio48e_gpio *const dio48egpio = lock_arg;
12862306a36Sopenharmony_ci	unsigned long flags;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	raw_spin_lock_irqsave(&dio48egpio->lock, flags);
13162306a36Sopenharmony_ci	dio48egpio->flags = flags;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic void dio48e_regmap_unlock(void *lock_arg) __releases(&dio48egpio->lock)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct dio48e_gpio *const dio48egpio = lock_arg;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&dio48egpio->lock, dio48egpio->flags);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic void pit_regmap_lock(void *lock_arg) __acquires(&dio48egpio->lock)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	struct dio48e_gpio *const dio48egpio = lock_arg;
14462306a36Sopenharmony_ci	unsigned long flags;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	raw_spin_lock_irqsave(&dio48egpio->lock, flags);
14762306a36Sopenharmony_ci	dio48egpio->flags = flags;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	iowrite8(0x00, dio48egpio->regs + DIO48E_ENABLE_COUNTER_TIMER_ADDRESSING);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic void pit_regmap_unlock(void *lock_arg) __releases(&dio48egpio->lock)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct dio48e_gpio *const dio48egpio = lock_arg;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	ioread8(dio48egpio->regs + DIO48E_DISABLE_COUNTER_TIMER_ADDRESSING);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&dio48egpio->lock, dio48egpio->flags);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int dio48e_handle_mask_sync(const int index,
16262306a36Sopenharmony_ci				   const unsigned int mask_buf_def,
16362306a36Sopenharmony_ci				   const unsigned int mask_buf,
16462306a36Sopenharmony_ci				   void *const irq_drv_data)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct dio48e_gpio *const dio48egpio = irq_drv_data;
16762306a36Sopenharmony_ci	const unsigned int prev_mask = dio48egpio->irq_mask;
16862306a36Sopenharmony_ci	int err;
16962306a36Sopenharmony_ci	unsigned int val;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* exit early if no change since the previous mask */
17262306a36Sopenharmony_ci	if (mask_buf == prev_mask)
17362306a36Sopenharmony_ci		return 0;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* remember the current mask for the next mask sync */
17662306a36Sopenharmony_ci	dio48egpio->irq_mask = mask_buf;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* if all previously masked, enable interrupts when unmasking */
17962306a36Sopenharmony_ci	if (prev_mask == mask_buf_def) {
18062306a36Sopenharmony_ci		err = regmap_write(dio48egpio->map, DIO48E_CLEAR_INTERRUPT, 0x00);
18162306a36Sopenharmony_ci		if (err)
18262306a36Sopenharmony_ci			return err;
18362306a36Sopenharmony_ci		return regmap_write(dio48egpio->map, DIO48E_ENABLE_INTERRUPT, 0x00);
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	/* if all are currently masked, disable interrupts */
18762306a36Sopenharmony_ci	if (mask_buf == mask_buf_def)
18862306a36Sopenharmony_ci		return regmap_read(dio48egpio->map, DIO48E_DISABLE_INTERRUPT, &val);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return 0;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci#define DIO48E_NGPIO 48
19462306a36Sopenharmony_cistatic const char *dio48e_names[DIO48E_NGPIO] = {
19562306a36Sopenharmony_ci	"PPI Group 0 Port A 0", "PPI Group 0 Port A 1", "PPI Group 0 Port A 2",
19662306a36Sopenharmony_ci	"PPI Group 0 Port A 3", "PPI Group 0 Port A 4", "PPI Group 0 Port A 5",
19762306a36Sopenharmony_ci	"PPI Group 0 Port A 6", "PPI Group 0 Port A 7",	"PPI Group 0 Port B 0",
19862306a36Sopenharmony_ci	"PPI Group 0 Port B 1", "PPI Group 0 Port B 2", "PPI Group 0 Port B 3",
19962306a36Sopenharmony_ci	"PPI Group 0 Port B 4", "PPI Group 0 Port B 5", "PPI Group 0 Port B 6",
20062306a36Sopenharmony_ci	"PPI Group 0 Port B 7", "PPI Group 0 Port C 0", "PPI Group 0 Port C 1",
20162306a36Sopenharmony_ci	"PPI Group 0 Port C 2", "PPI Group 0 Port C 3", "PPI Group 0 Port C 4",
20262306a36Sopenharmony_ci	"PPI Group 0 Port C 5", "PPI Group 0 Port C 6", "PPI Group 0 Port C 7",
20362306a36Sopenharmony_ci	"PPI Group 1 Port A 0", "PPI Group 1 Port A 1", "PPI Group 1 Port A 2",
20462306a36Sopenharmony_ci	"PPI Group 1 Port A 3", "PPI Group 1 Port A 4", "PPI Group 1 Port A 5",
20562306a36Sopenharmony_ci	"PPI Group 1 Port A 6", "PPI Group 1 Port A 7",	"PPI Group 1 Port B 0",
20662306a36Sopenharmony_ci	"PPI Group 1 Port B 1", "PPI Group 1 Port B 2", "PPI Group 1 Port B 3",
20762306a36Sopenharmony_ci	"PPI Group 1 Port B 4", "PPI Group 1 Port B 5", "PPI Group 1 Port B 6",
20862306a36Sopenharmony_ci	"PPI Group 1 Port B 7", "PPI Group 1 Port C 0", "PPI Group 1 Port C 1",
20962306a36Sopenharmony_ci	"PPI Group 1 Port C 2", "PPI Group 1 Port C 3", "PPI Group 1 Port C 4",
21062306a36Sopenharmony_ci	"PPI Group 1 Port C 5", "PPI Group 1 Port C 6", "PPI Group 1 Port C 7"
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic int dio48e_irq_init_hw(struct regmap *const map)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	unsigned int val;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	/* Disable IRQ by default */
21862306a36Sopenharmony_ci	return regmap_read(map, DIO48E_DISABLE_INTERRUPT, &val);
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int dio48e_probe(struct device *dev, unsigned int id)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	const char *const name = dev_name(dev);
22462306a36Sopenharmony_ci	struct i8255_regmap_config config = {};
22562306a36Sopenharmony_ci	void __iomem *regs;
22662306a36Sopenharmony_ci	struct regmap *map;
22762306a36Sopenharmony_ci	struct regmap_config dio48e_regmap_config;
22862306a36Sopenharmony_ci	struct regmap_config pit_regmap_config;
22962306a36Sopenharmony_ci	struct i8254_regmap_config pit_config;
23062306a36Sopenharmony_ci	int err;
23162306a36Sopenharmony_ci	struct regmap_irq_chip *chip;
23262306a36Sopenharmony_ci	struct dio48e_gpio *dio48egpio;
23362306a36Sopenharmony_ci	struct regmap_irq_chip_data *chip_data;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (!devm_request_region(dev, base[id], DIO48E_EXTENT, name)) {
23662306a36Sopenharmony_ci		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
23762306a36Sopenharmony_ci			base[id], base[id] + DIO48E_EXTENT);
23862306a36Sopenharmony_ci		return -EBUSY;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	dio48egpio = devm_kzalloc(dev, sizeof(*dio48egpio), GFP_KERNEL);
24262306a36Sopenharmony_ci	if (!dio48egpio)
24362306a36Sopenharmony_ci		return -ENOMEM;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	regs = devm_ioport_map(dev, base[id], DIO48E_EXTENT);
24662306a36Sopenharmony_ci	if (!regs)
24762306a36Sopenharmony_ci		return -ENOMEM;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	dio48egpio->regs = regs;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	raw_spin_lock_init(&dio48egpio->lock);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	dio48e_regmap_config = (struct regmap_config) {
25462306a36Sopenharmony_ci		.reg_bits = 8,
25562306a36Sopenharmony_ci		.reg_stride = 1,
25662306a36Sopenharmony_ci		.val_bits = 8,
25762306a36Sopenharmony_ci		.lock = dio48e_regmap_lock,
25862306a36Sopenharmony_ci		.unlock = dio48e_regmap_unlock,
25962306a36Sopenharmony_ci		.lock_arg = dio48egpio,
26062306a36Sopenharmony_ci		.io_port = true,
26162306a36Sopenharmony_ci		.wr_table = &dio48e_wr_table,
26262306a36Sopenharmony_ci		.rd_table = &dio48e_rd_table,
26362306a36Sopenharmony_ci		.volatile_table = &dio48e_volatile_table,
26462306a36Sopenharmony_ci		.precious_table = &dio48e_precious_table,
26562306a36Sopenharmony_ci		.cache_type = REGCACHE_FLAT,
26662306a36Sopenharmony_ci	};
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	map = devm_regmap_init_mmio(dev, regs, &dio48e_regmap_config);
26962306a36Sopenharmony_ci	if (IS_ERR(map))
27062306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(map),
27162306a36Sopenharmony_ci				     "Unable to initialize register map\n");
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	dio48egpio->map = map;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	pit_regmap_config = (struct regmap_config) {
27662306a36Sopenharmony_ci		.name = "i8254",
27762306a36Sopenharmony_ci		.reg_bits = 8,
27862306a36Sopenharmony_ci		.reg_stride = 1,
27962306a36Sopenharmony_ci		.val_bits = 8,
28062306a36Sopenharmony_ci		.lock = pit_regmap_lock,
28162306a36Sopenharmony_ci		.unlock = pit_regmap_unlock,
28262306a36Sopenharmony_ci		.lock_arg = dio48egpio,
28362306a36Sopenharmony_ci		.io_port = true,
28462306a36Sopenharmony_ci		.wr_table = &pit_wr_table,
28562306a36Sopenharmony_ci		.rd_table = &pit_rd_table,
28662306a36Sopenharmony_ci	};
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	pit_config.map = devm_regmap_init_mmio(dev, regs, &pit_regmap_config);
28962306a36Sopenharmony_ci	if (IS_ERR(pit_config.map))
29062306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(pit_config.map),
29162306a36Sopenharmony_ci				     "Unable to initialize i8254 register map\n");
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
29462306a36Sopenharmony_ci	if (!chip)
29562306a36Sopenharmony_ci		return -ENOMEM;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	chip->name = name;
29862306a36Sopenharmony_ci	chip->mask_base = DIO48E_ENABLE_INTERRUPT;
29962306a36Sopenharmony_ci	chip->ack_base = DIO48E_CLEAR_INTERRUPT;
30062306a36Sopenharmony_ci	chip->no_status = true;
30162306a36Sopenharmony_ci	chip->num_regs = 1;
30262306a36Sopenharmony_ci	chip->irqs = dio48e_regmap_irqs;
30362306a36Sopenharmony_ci	chip->num_irqs = ARRAY_SIZE(dio48e_regmap_irqs);
30462306a36Sopenharmony_ci	chip->handle_mask_sync = dio48e_handle_mask_sync;
30562306a36Sopenharmony_ci	chip->irq_drv_data = dio48egpio;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* Initialize to prevent spurious interrupts before we're ready */
30862306a36Sopenharmony_ci	err = dio48e_irq_init_hw(map);
30962306a36Sopenharmony_ci	if (err)
31062306a36Sopenharmony_ci		return err;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	err = devm_regmap_add_irq_chip(dev, map, irq[id], 0, 0, chip, &chip_data);
31362306a36Sopenharmony_ci	if (err)
31462306a36Sopenharmony_ci		return dev_err_probe(dev, err, "IRQ registration failed\n");
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	pit_config.parent = dev;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	err = devm_i8254_regmap_register(dev, &pit_config);
31962306a36Sopenharmony_ci	if (err)
32062306a36Sopenharmony_ci		return err;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	config.parent = dev;
32362306a36Sopenharmony_ci	config.map = map;
32462306a36Sopenharmony_ci	config.num_ppi = DIO48E_NUM_PPI;
32562306a36Sopenharmony_ci	config.names = dio48e_names;
32662306a36Sopenharmony_ci	config.domain = regmap_irq_get_domain(chip_data);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	return devm_i8255_regmap_register(dev, &config);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic struct isa_driver dio48e_driver = {
33262306a36Sopenharmony_ci	.probe = dio48e_probe,
33362306a36Sopenharmony_ci	.driver = {
33462306a36Sopenharmony_ci		.name = "104-dio-48e"
33562306a36Sopenharmony_ci	},
33662306a36Sopenharmony_ci};
33762306a36Sopenharmony_cimodule_isa_driver_with_irq(dio48e_driver, num_dio48e, num_irq);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ciMODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
34062306a36Sopenharmony_ciMODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver");
34162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
34262306a36Sopenharmony_ciMODULE_IMPORT_NS(I8254);
343