Merge tag 'ubifs-for-linus-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-block.git] / drivers / gpio / gpio-pcie-idio-24.c
CommitLineData
58556204
WBG
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * GPIO driver for the ACCES PCIe-IDIO-24 family
4 * Copyright (C) 2018 William Breathitt Gray
5 *
58556204
WBG
6 * This driver supports the following ACCES devices: PCIe-IDIO-24,
7 * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
8 */
1a200a39 9#include <linux/bits.h>
58556204 10#include <linux/device.h>
1a200a39
WBG
11#include <linux/err.h>
12#include <linux/gpio/regmap.h>
13#include <linux/irq.h>
58556204
WBG
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/pci.h>
1a200a39 17#include <linux/regmap.h>
58556204
WBG
18#include <linux/spinlock.h>
19#include <linux/types.h>
20
10a2f11d
AT
21/*
22 * PLX PEX8311 PCI LCS_INTCSR Interrupt Control/Status
23 *
24 * Bit: Description
25 * 0: Enable Interrupt Sources (Bit 0)
26 * 1: Enable Interrupt Sources (Bit 1)
27 * 2: Generate Internal PCI Bus Internal SERR# Interrupt
28 * 3: Mailbox Interrupt Enable
29 * 4: Power Management Interrupt Enable
30 * 5: Power Management Interrupt
31 * 6: Slave Read Local Data Parity Check Error Enable
32 * 7: Slave Read Local Data Parity Check Error Status
33 * 8: Internal PCI Wire Interrupt Enable
34 * 9: PCI Express Doorbell Interrupt Enable
35 * 10: PCI Abort Interrupt Enable
36 * 11: Local Interrupt Input Enable
37 * 12: Retry Abort Enable
38 * 13: PCI Express Doorbell Interrupt Active
39 * 14: PCI Abort Interrupt Active
40 * 15: Local Interrupt Input Active
41 * 16: Local Interrupt Output Enable
42 * 17: Local Doorbell Interrupt Enable
43 * 18: DMA Channel 0 Interrupt Enable
44 * 19: DMA Channel 1 Interrupt Enable
45 * 20: Local Doorbell Interrupt Active
46 * 21: DMA Channel 0 Interrupt Active
47 * 22: DMA Channel 1 Interrupt Active
48 * 23: Built-In Self-Test (BIST) Interrupt Active
49 * 24: Direct Master was the Bus Master during a Master or Target Abort
50 * 25: DMA Channel 0 was the Bus Master during a Master or Target Abort
51 * 26: DMA Channel 1 was the Bus Master during a Master or Target Abort
52 * 27: Target Abort after internal 256 consecutive Master Retrys
53 * 28: PCI Bus wrote data to LCS_MBOX0
54 * 29: PCI Bus wrote data to LCS_MBOX1
55 * 30: PCI Bus wrote data to LCS_MBOX2
56 * 31: PCI Bus wrote data to LCS_MBOX3
57 */
58#define PLX_PEX8311_PCI_LCS_INTCSR 0x68
59#define INTCSR_INTERNAL_PCI_WIRE BIT(8)
60#define INTCSR_LOCAL_INPUT BIT(11)
1a200a39
WBG
61#define IDIO_24_ENABLE_IRQ (INTCSR_INTERNAL_PCI_WIRE | INTCSR_LOCAL_INPUT)
62
63#define IDIO_24_OUT_BASE 0x0
64#define IDIO_24_TTLCMOS_OUT_REG 0x3
65#define IDIO_24_IN_BASE 0x4
66#define IDIO_24_TTLCMOS_IN_REG 0x7
67#define IDIO_24_COS_STATUS_BASE 0x8
68#define IDIO_24_CONTROL_REG 0xC
69#define IDIO_24_COS_ENABLE 0xE
70#define IDIO_24_SOFT_RESET 0xF
71
72#define CONTROL_REG_OUT_MODE BIT(1)
73
74#define COS_ENABLE_RISING BIT(1)
75#define COS_ENABLE_FALLING BIT(4)
76#define COS_ENABLE_BOTH (COS_ENABLE_RISING | COS_ENABLE_FALLING)
77
78static const struct regmap_config pex8311_intcsr_regmap_config = {
79 .name = "pex8311_intcsr",
80 .reg_bits = 32,
81 .reg_stride = 1,
82 .reg_base = PLX_PEX8311_PCI_LCS_INTCSR,
83 .val_bits = 32,
84 .io_port = true,
85};
10a2f11d 86
1a200a39
WBG
87static const struct regmap_range idio_24_wr_ranges[] = {
88 regmap_reg_range(0x0, 0x3), regmap_reg_range(0x8, 0xC),
89 regmap_reg_range(0xE, 0xF),
90};
91static const struct regmap_range idio_24_rd_ranges[] = {
92 regmap_reg_range(0x0, 0xC), regmap_reg_range(0xE, 0xF),
93};
94static const struct regmap_range idio_24_volatile_ranges[] = {
95 regmap_reg_range(0x4, 0xB), regmap_reg_range(0xF, 0xF),
96};
97static const struct regmap_access_table idio_24_wr_table = {
98 .yes_ranges = idio_24_wr_ranges,
99 .n_yes_ranges = ARRAY_SIZE(idio_24_wr_ranges),
100};
101static const struct regmap_access_table idio_24_rd_table = {
102 .yes_ranges = idio_24_rd_ranges,
103 .n_yes_ranges = ARRAY_SIZE(idio_24_rd_ranges),
104};
105static const struct regmap_access_table idio_24_volatile_table = {
106 .yes_ranges = idio_24_volatile_ranges,
107 .n_yes_ranges = ARRAY_SIZE(idio_24_volatile_ranges),
108};
109
110static const struct regmap_config idio_24_regmap_config = {
111 .reg_bits = 8,
112 .reg_stride = 1,
113 .val_bits = 8,
114 .io_port = true,
115 .wr_table = &idio_24_wr_table,
116 .rd_table = &idio_24_rd_table,
117 .volatile_table = &idio_24_volatile_table,
118 .cache_type = REGCACHE_FLAT,
119 .use_raw_spinlock = true,
120};
121
122#define IDIO_24_NGPIO_PER_REG 8
123#define IDIO_24_REGMAP_IRQ(_id) \
124 [24 + _id] = { \
125 .reg_offset = (_id) / IDIO_24_NGPIO_PER_REG, \
126 .mask = BIT((_id) % IDIO_24_NGPIO_PER_REG), \
127 .type = { .types_supported = IRQ_TYPE_EDGE_BOTH }, \
128 }
129#define IDIO_24_IIN_IRQ(_id) IDIO_24_REGMAP_IRQ(_id)
130#define IDIO_24_TTL_IRQ(_id) IDIO_24_REGMAP_IRQ(24 + _id)
131
132static const struct regmap_irq idio_24_regmap_irqs[] = {
133 IDIO_24_IIN_IRQ(0), IDIO_24_IIN_IRQ(1), IDIO_24_IIN_IRQ(2), /* IIN 0-2 */
134 IDIO_24_IIN_IRQ(3), IDIO_24_IIN_IRQ(4), IDIO_24_IIN_IRQ(5), /* IIN 3-5 */
135 IDIO_24_IIN_IRQ(6), IDIO_24_IIN_IRQ(7), IDIO_24_IIN_IRQ(8), /* IIN 6-8 */
136 IDIO_24_IIN_IRQ(9), IDIO_24_IIN_IRQ(10), IDIO_24_IIN_IRQ(11), /* IIN 9-11 */
137 IDIO_24_IIN_IRQ(12), IDIO_24_IIN_IRQ(13), IDIO_24_IIN_IRQ(14), /* IIN 12-14 */
138 IDIO_24_IIN_IRQ(15), IDIO_24_IIN_IRQ(16), IDIO_24_IIN_IRQ(17), /* IIN 15-17 */
139 IDIO_24_IIN_IRQ(18), IDIO_24_IIN_IRQ(19), IDIO_24_IIN_IRQ(20), /* IIN 18-20 */
140 IDIO_24_IIN_IRQ(21), IDIO_24_IIN_IRQ(22), IDIO_24_IIN_IRQ(23), /* IIN 21-23 */
141 IDIO_24_TTL_IRQ(0), IDIO_24_TTL_IRQ(1), IDIO_24_TTL_IRQ(2), /* TTL 0-2 */
142 IDIO_24_TTL_IRQ(3), IDIO_24_TTL_IRQ(4), IDIO_24_TTL_IRQ(5), /* TTL 3-5 */
143 IDIO_24_TTL_IRQ(6), IDIO_24_TTL_IRQ(7), /* TTL 6-7 */
58556204
WBG
144};
145
146/**
147 * struct idio_24_gpio - GPIO device private data structure
1a200a39 148 * @map: regmap for the device
58556204 149 * @lock: synchronization lock to prevent I/O race conditions
1a200a39 150 * @irq_type: type configuration for IRQs
58556204
WBG
151 */
152struct idio_24_gpio {
1a200a39 153 struct regmap *map;
58556204 154 raw_spinlock_t lock;
1a200a39 155 u8 irq_type;
58556204
WBG
156};
157
1a200a39
WBG
158static int idio_24_handle_mask_sync(const int index, const unsigned int mask_buf_def,
159 const unsigned int mask_buf, void *const irq_drv_data)
58556204 160{
1a200a39
WBG
161 const unsigned int type_mask = COS_ENABLE_BOTH << index;
162 struct idio_24_gpio *const idio24gpio = irq_drv_data;
163 u8 type;
164 int ret;
58556204 165
1a200a39 166 raw_spin_lock(&idio24gpio->lock);
58556204 167
1a200a39
WBG
168 /* if all are masked, then disable interrupts, else set to type */
169 type = (mask_buf == mask_buf_def) ? ~type_mask : idio24gpio->irq_type;
58556204 170
1a200a39 171 ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, type_mask, type);
58556204 172
1a200a39 173 raw_spin_unlock(&idio24gpio->lock);
ca370815 174
1a200a39 175 return ret;
ca370815
WBG
176}
177
1a200a39
WBG
178static int idio_24_set_type_config(unsigned int **const buf, const unsigned int type,
179 const struct regmap_irq *const irq_data, const int idx,
180 void *const irq_drv_data)
58556204 181{
1a200a39
WBG
182 const unsigned int offset = irq_data->reg_offset;
183 const unsigned int rising = COS_ENABLE_RISING << offset;
184 const unsigned int falling = COS_ENABLE_FALLING << offset;
185 const unsigned int mask = COS_ENABLE_BOTH << offset;
186 struct idio_24_gpio *const idio24gpio = irq_drv_data;
187 unsigned int new;
188 unsigned int cos_enable;
189 int ret;
190
191 switch (type) {
192 case IRQ_TYPE_EDGE_RISING:
193 new = rising;
194 break;
195 case IRQ_TYPE_EDGE_FALLING:
196 new = falling;
197 break;
198 case IRQ_TYPE_EDGE_BOTH:
199 new = mask;
200 break;
201 default:
202 return -EINVAL;
c586aa8f 203 }
58556204 204
1a200a39 205 raw_spin_lock(&idio24gpio->lock);
58556204 206
1a200a39
WBG
207 /* replace old bitmap with new bitmap */
208 idio24gpio->irq_type = (idio24gpio->irq_type & ~mask) | (new & mask);
58556204 209
1a200a39
WBG
210 ret = regmap_read(idio24gpio->map, IDIO_24_COS_ENABLE, &cos_enable);
211 if (ret)
212 goto exit_unlock;
58556204 213
1a200a39
WBG
214 /* if COS is currently enabled then update the edge type */
215 if (cos_enable & mask) {
216 ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, mask,
217 idio24gpio->irq_type);
218 if (ret)
219 goto exit_unlock;
58556204
WBG
220 }
221
1a200a39
WBG
222exit_unlock:
223 raw_spin_unlock(&idio24gpio->lock);
33886f92 224
1a200a39 225 return ret;
58556204
WBG
226}
227
1a200a39
WBG
228static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
229 const unsigned int offset, unsigned int *const reg,
230 unsigned int *const mask)
58556204 231{
1a200a39
WBG
232 const unsigned int out_stride = offset / IDIO_24_NGPIO_PER_REG;
233 const unsigned int in_stride = (offset - 24) / IDIO_24_NGPIO_PER_REG;
234 struct regmap *const map = gpio_regmap_get_drvdata(gpio);
235 int err;
236 unsigned int ctrl_reg;
58556204 237
1a200a39
WBG
238 switch (base) {
239 case IDIO_24_OUT_BASE:
240 *mask = BIT(offset % IDIO_24_NGPIO_PER_REG);
58556204 241
1a200a39
WBG
242 /* FET Outputs */
243 if (offset < 24) {
244 *reg = IDIO_24_OUT_BASE + out_stride;
245 return 0;
246 }
58556204 247
1a200a39
WBG
248 /* Isolated Inputs */
249 if (offset < 48) {
250 *reg = IDIO_24_IN_BASE + in_stride;
251 return 0;
252 }
58556204 253
1a200a39
WBG
254 err = regmap_read(map, IDIO_24_CONTROL_REG, &ctrl_reg);
255 if (err)
256 return err;
58556204 257
1a200a39
WBG
258 /* TTL/CMOS Outputs */
259 if (ctrl_reg & CONTROL_REG_OUT_MODE) {
260 *reg = IDIO_24_TTLCMOS_OUT_REG;
261 return 0;
262 }
58556204 263
1a200a39
WBG
264 /* TTL/CMOS Inputs */
265 *reg = IDIO_24_TTLCMOS_IN_REG;
266 return 0;
267 case IDIO_24_CONTROL_REG:
268 /* We can only set direction for TTL/CMOS lines */
269 if (offset < 48)
270 return -EOPNOTSUPP;
271
272 *reg = IDIO_24_CONTROL_REG;
273 *mask = CONTROL_REG_OUT_MODE;
274 return 0;
275 default:
276 /* Should never reach this path */
58556204 277 return -EINVAL;
1a200a39 278 }
58556204
WBG
279}
280
281#define IDIO_24_NGPIO 56
282static const char *idio_24_names[IDIO_24_NGPIO] = {
283 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
284 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
285 "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
286 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
287 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
288 "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
289 "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
290};
291
292static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
293{
294 struct device *const dev = &pdev->dev;
295 struct idio_24_gpio *idio24gpio;
296 int err;
10a2f11d 297 const size_t pci_plx_bar_index = 1;
58556204
WBG
298 const size_t pci_bar_index = 2;
299 const char *const name = pci_name(pdev);
1a200a39
WBG
300 struct gpio_regmap_config gpio_config = {};
301 void __iomem *pex8311_regs;
302 void __iomem *idio_24_regs;
303 struct regmap *intcsr_map;
304 struct regmap_irq_chip *chip;
305 struct regmap_irq_chip_data *chip_data;
58556204
WBG
306
307 err = pcim_enable_device(pdev);
308 if (err) {
309 dev_err(dev, "Failed to enable PCI device (%d)\n", err);
310 return err;
311 }
312
10a2f11d 313 err = pcim_iomap_regions(pdev, BIT(pci_plx_bar_index) | BIT(pci_bar_index), name);
58556204
WBG
314 if (err) {
315 dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
316 return err;
317 }
318
1a200a39
WBG
319 pex8311_regs = pcim_iomap_table(pdev)[pci_plx_bar_index];
320 idio_24_regs = pcim_iomap_table(pdev)[pci_bar_index];
321
322 intcsr_map = devm_regmap_init_mmio(dev, pex8311_regs, &pex8311_intcsr_regmap_config);
323 if (IS_ERR(intcsr_map))
324 return dev_err_probe(dev, PTR_ERR(intcsr_map),
325 "Unable to initialize PEX8311 register map\n");
326
327 idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
328 if (!idio24gpio)
329 return -ENOMEM;
330
331 idio24gpio->map = devm_regmap_init_mmio(dev, idio_24_regs, &idio_24_regmap_config);
332 if (IS_ERR(idio24gpio->map))
333 return dev_err_probe(dev, PTR_ERR(idio24gpio->map),
334 "Unable to initialize register map\n");
866e863e 335
58556204
WBG
336 raw_spin_lock_init(&idio24gpio->lock);
337
1a200a39
WBG
338 /* Initialize all IRQ type configuration to IRQ_TYPE_EDGE_BOTH */
339 idio24gpio->irq_type = GENMASK(7, 0);
340
341 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
342 if (!chip)
343 return -ENOMEM;
344
345 chip->name = name;
346 chip->status_base = IDIO_24_COS_STATUS_BASE;
347 chip->mask_base = IDIO_24_COS_ENABLE;
348 chip->ack_base = IDIO_24_COS_STATUS_BASE;
349 chip->num_regs = 4;
350 chip->irqs = idio_24_regmap_irqs;
351 chip->num_irqs = ARRAY_SIZE(idio_24_regmap_irqs);
352 chip->handle_mask_sync = idio_24_handle_mask_sync;
353 chip->set_type_config = idio_24_set_type_config;
354 chip->irq_drv_data = idio24gpio;
355
58556204 356 /* Software board reset */
1a200a39
WBG
357 err = regmap_write(idio24gpio->map, IDIO_24_SOFT_RESET, 0);
358 if (err)
359 return err;
10a2f11d
AT
360 /*
361 * enable PLX PEX8311 internal PCI wire interrupt and local interrupt
362 * input
363 */
1a200a39
WBG
364 err = regmap_update_bits(intcsr_map, 0x0, IDIO_24_ENABLE_IRQ, IDIO_24_ENABLE_IRQ);
365 if (err)
58556204 366 return err;
58556204 367
1a200a39
WBG
368 err = devm_regmap_add_irq_chip(dev, idio24gpio->map, pdev->irq, 0, 0, chip, &chip_data);
369 if (err)
370 return dev_err_probe(dev, err, "IRQ registration failed\n");
371
372 gpio_config.parent = dev;
373 gpio_config.regmap = idio24gpio->map;
374 gpio_config.ngpio = IDIO_24_NGPIO;
375 gpio_config.names = idio_24_names;
376 gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE);
377 gpio_config.reg_set_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE);
378 gpio_config.reg_dir_out_base = GPIO_REGMAP_ADDR(IDIO_24_CONTROL_REG);
379 gpio_config.ngpio_per_reg = IDIO_24_NGPIO_PER_REG;
380 gpio_config.irq_domain = regmap_irq_get_domain(chip_data);
381 gpio_config.reg_mask_xlate = idio_24_reg_mask_xlate;
382 gpio_config.drvdata = idio24gpio->map;
383
384 return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
58556204
WBG
385}
386
387static const struct pci_device_id idio_24_pci_dev_id[] = {
388 { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
389 { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
390 { 0 }
391};
392MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
393
394static struct pci_driver idio_24_driver = {
395 .name = "pcie-idio-24",
396 .id_table = idio_24_pci_dev_id,
397 .probe = idio_24_probe
398};
399
400module_pci_driver(idio_24_driver);
401
402MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
403MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
404MODULE_LICENSE("GPL v2");