1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * GPIO driver for Exar XR17V35X chip |
4 | * |
5 | * Copyright (C) 2015 Sudip Mukherjee <sudip.mukherjee@codethink.co.uk> |
6 | */ |
7 | |
8 | #include <linux/bitops.h> |
9 | #include <linux/device.h> |
10 | #include <linux/gpio/driver.h> |
11 | #include <linux/idr.h> |
12 | #include <linux/init.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/module.h> |
15 | #include <linux/pci.h> |
16 | #include <linux/platform_device.h> |
17 | #include <linux/regmap.h> |
18 | |
19 | #define EXAR_OFFSET_MPIOLVL_LO 0x90 |
20 | #define EXAR_OFFSET_MPIOSEL_LO 0x93 |
21 | #define EXAR_OFFSET_MPIOLVL_HI 0x96 |
22 | #define EXAR_OFFSET_MPIOSEL_HI 0x99 |
23 | |
24 | /* |
25 | * The Device Configuration and UART Configuration Registers |
26 | * for each UART channel take 1KB of memory address space. |
27 | */ |
28 | #define EXAR_UART_CHANNEL_SIZE 0x400 |
29 | |
30 | #define DRIVER_NAME "gpio_exar" |
31 | |
32 | static DEFINE_IDA(ida_index); |
33 | |
34 | struct exar_gpio_chip { |
35 | struct gpio_chip gpio_chip; |
36 | struct regmap *regmap; |
37 | int index; |
38 | char name[20]; |
39 | unsigned int first_pin; |
40 | /* |
41 | * The offset to the cascaded device's (if existing) |
42 | * Device Configuration Registers. |
43 | */ |
44 | unsigned int cascaded_offset; |
45 | }; |
46 | |
47 | static unsigned int |
48 | exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset) |
49 | { |
50 | unsigned int pin = exar_gpio->first_pin + (offset % 16); |
51 | unsigned int cascaded = offset / 16; |
52 | unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO; |
53 | |
54 | return addr + (cascaded ? exar_gpio->cascaded_offset : 0); |
55 | } |
56 | |
57 | static unsigned int |
58 | exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset) |
59 | { |
60 | unsigned int pin = exar_gpio->first_pin + (offset % 16); |
61 | unsigned int cascaded = offset / 16; |
62 | unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO; |
63 | |
64 | return addr + (cascaded ? exar_gpio->cascaded_offset : 0); |
65 | } |
66 | |
67 | static unsigned int |
68 | exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset) |
69 | { |
70 | unsigned int pin = exar_gpio->first_pin + (offset % 16); |
71 | |
72 | return pin % 8; |
73 | } |
74 | |
75 | static int exar_get_direction(struct gpio_chip *chip, unsigned int offset) |
76 | { |
77 | struct exar_gpio_chip *exar_gpio = gpiochip_get_data(gc: chip); |
78 | unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); |
79 | unsigned int bit = exar_offset_to_bit(exar_gpio, offset); |
80 | |
81 | if (regmap_test_bits(map: exar_gpio->regmap, reg: addr, BIT(bit))) |
82 | return GPIO_LINE_DIRECTION_IN; |
83 | |
84 | return GPIO_LINE_DIRECTION_OUT; |
85 | } |
86 | |
87 | static int exar_get_value(struct gpio_chip *chip, unsigned int offset) |
88 | { |
89 | struct exar_gpio_chip *exar_gpio = gpiochip_get_data(gc: chip); |
90 | unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); |
91 | unsigned int bit = exar_offset_to_bit(exar_gpio, offset); |
92 | |
93 | return !!(regmap_test_bits(map: exar_gpio->regmap, reg: addr, BIT(bit))); |
94 | } |
95 | |
96 | static void exar_set_value(struct gpio_chip *chip, unsigned int offset, |
97 | int value) |
98 | { |
99 | struct exar_gpio_chip *exar_gpio = gpiochip_get_data(gc: chip); |
100 | unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); |
101 | unsigned int bit = exar_offset_to_bit(exar_gpio, offset); |
102 | |
103 | if (value) |
104 | regmap_set_bits(map: exar_gpio->regmap, reg: addr, BIT(bit)); |
105 | else |
106 | regmap_clear_bits(map: exar_gpio->regmap, reg: addr, BIT(bit)); |
107 | } |
108 | |
109 | static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, |
110 | int value) |
111 | { |
112 | struct exar_gpio_chip *exar_gpio = gpiochip_get_data(gc: chip); |
113 | unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); |
114 | unsigned int bit = exar_offset_to_bit(exar_gpio, offset); |
115 | |
116 | exar_set_value(chip, offset, value); |
117 | regmap_clear_bits(map: exar_gpio->regmap, reg: addr, BIT(bit)); |
118 | |
119 | return 0; |
120 | } |
121 | |
122 | static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) |
123 | { |
124 | struct exar_gpio_chip *exar_gpio = gpiochip_get_data(gc: chip); |
125 | unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); |
126 | unsigned int bit = exar_offset_to_bit(exar_gpio, offset); |
127 | |
128 | regmap_set_bits(map: exar_gpio->regmap, reg: addr, BIT(bit)); |
129 | |
130 | return 0; |
131 | } |
132 | |
133 | static void exar_devm_ida_free(void *data) |
134 | { |
135 | struct exar_gpio_chip *exar_gpio = data; |
136 | |
137 | ida_free(&ida_index, id: exar_gpio->index); |
138 | } |
139 | |
140 | static const struct regmap_config exar_regmap_config = { |
141 | .name = "exar-gpio" , |
142 | .reg_bits = 16, |
143 | .val_bits = 8, |
144 | .io_port = true, |
145 | }; |
146 | |
147 | static int gpio_exar_probe(struct platform_device *pdev) |
148 | { |
149 | struct device *dev = &pdev->dev; |
150 | struct pci_dev *pcidev = to_pci_dev(dev->parent); |
151 | struct exar_gpio_chip *exar_gpio; |
152 | u32 first_pin, ngpios; |
153 | void __iomem *p; |
154 | int index, ret; |
155 | |
156 | /* |
157 | * The UART driver must have mapped region 0 prior to registering this |
158 | * device - use it. |
159 | */ |
160 | p = pcim_iomap_table(pdev: pcidev)[0]; |
161 | if (!p) |
162 | return -ENOMEM; |
163 | |
164 | ret = device_property_read_u32(dev, propname: "exar,first-pin" , val: &first_pin); |
165 | if (ret) |
166 | return ret; |
167 | |
168 | ret = device_property_read_u32(dev, propname: "ngpios" , val: &ngpios); |
169 | if (ret) |
170 | return ret; |
171 | |
172 | exar_gpio = devm_kzalloc(dev, size: sizeof(*exar_gpio), GFP_KERNEL); |
173 | if (!exar_gpio) |
174 | return -ENOMEM; |
175 | |
176 | /* |
177 | * If cascaded, secondary xr17v354 or xr17v358 have the same amount |
178 | * of MPIOs as their primaries and the last 4 bits of the primary's |
179 | * PCI Device ID is the number of its UART channels. |
180 | */ |
181 | if (pcidev->device & GENMASK(15, 12)) { |
182 | ngpios += ngpios; |
183 | exar_gpio->cascaded_offset = (pcidev->device & GENMASK(3, 0)) * |
184 | EXAR_UART_CHANNEL_SIZE; |
185 | } |
186 | |
187 | /* |
188 | * We don't need to check the return values of mmio regmap operations (unless |
189 | * the regmap has a clock attached which is not the case here). |
190 | */ |
191 | exar_gpio->regmap = devm_regmap_init_mmio(dev, p, &exar_regmap_config); |
192 | if (IS_ERR(ptr: exar_gpio->regmap)) |
193 | return PTR_ERR(ptr: exar_gpio->regmap); |
194 | |
195 | index = ida_alloc(ida: &ida_index, GFP_KERNEL); |
196 | if (index < 0) |
197 | return index; |
198 | |
199 | ret = devm_add_action_or_reset(dev, exar_devm_ida_free, exar_gpio); |
200 | if (ret) |
201 | return ret; |
202 | |
203 | sprintf(buf: exar_gpio->name, fmt: "exar_gpio%d" , index); |
204 | exar_gpio->gpio_chip.label = exar_gpio->name; |
205 | exar_gpio->gpio_chip.parent = dev; |
206 | exar_gpio->gpio_chip.direction_output = exar_direction_output; |
207 | exar_gpio->gpio_chip.direction_input = exar_direction_input; |
208 | exar_gpio->gpio_chip.get_direction = exar_get_direction; |
209 | exar_gpio->gpio_chip.get = exar_get_value; |
210 | exar_gpio->gpio_chip.set = exar_set_value; |
211 | exar_gpio->gpio_chip.base = -1; |
212 | exar_gpio->gpio_chip.ngpio = ngpios; |
213 | exar_gpio->index = index; |
214 | exar_gpio->first_pin = first_pin; |
215 | |
216 | ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio); |
217 | if (ret) |
218 | return ret; |
219 | |
220 | return 0; |
221 | } |
222 | |
223 | static struct platform_driver gpio_exar_driver = { |
224 | .probe = gpio_exar_probe, |
225 | .driver = { |
226 | .name = DRIVER_NAME, |
227 | }, |
228 | }; |
229 | |
230 | module_platform_driver(gpio_exar_driver); |
231 | |
232 | MODULE_ALIAS("platform:" DRIVER_NAME); |
233 | MODULE_DESCRIPTION("Exar GPIO driver" ); |
234 | MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>" ); |
235 | MODULE_LICENSE("GPL" ); |
236 | |