]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
6596e59e SM |
2 | /* |
3 | * GPIO driver for Exar XR17V35X chip | |
4 | * | |
5 | * Copyright (C) 2015 Sudip Mukherjee <[email protected]> | |
6596e59e | 6 | */ |
1bfaf129 | 7 | |
6596e59e SM |
8 | #include <linux/bitops.h> |
9 | #include <linux/device.h> | |
10 | #include <linux/gpio/driver.h> | |
26ced453 | 11 | #include <linux/idr.h> |
6596e59e SM |
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> | |
36fb7218 | 17 | #include <linux/regmap.h> |
6596e59e SM |
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 | ||
5134272f QC |
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 | ||
6596e59e SM |
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; | |
36fb7218 | 36 | struct regmap *regmap; |
6596e59e | 37 | int index; |
6596e59e | 38 | char name[20]; |
380b1e2f | 39 | unsigned int first_pin; |
5134272f QC |
40 | /* |
41 | * The offset to the cascaded device's (if existing) | |
42 | * Device Configuration Registers. | |
43 | */ | |
44 | unsigned int cascaded_offset; | |
6596e59e SM |
45 | }; |
46 | ||
696868d0 BG |
47 | static unsigned int |
48 | exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset) | |
49 | { | |
5134272f QC |
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); | |
696868d0 BG |
55 | } |
56 | ||
57 | static unsigned int | |
58 | exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset) | |
59 | { | |
5134272f QC |
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); | |
696868d0 BG |
65 | } |
66 | ||
67 | static unsigned int | |
68 | exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset) | |
69 | { | |
5134272f QC |
70 | unsigned int pin = exar_gpio->first_pin + (offset % 16); |
71 | ||
72 | return pin % 8; | |
696868d0 BG |
73 | } |
74 | ||
6596e59e SM |
75 | static int exar_get_direction(struct gpio_chip *chip, unsigned int offset) |
76 | { | |
380b1e2f | 77 | struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); |
696868d0 BG |
78 | unsigned int addr = exar_offset_to_sel_addr(exar_gpio, offset); |
79 | unsigned int bit = exar_offset_to_bit(exar_gpio, offset); | |
6596e59e | 80 | |
36fb7218 | 81 | if (regmap_test_bits(exar_gpio->regmap, addr, BIT(bit))) |
e42615ec MV |
82 | return GPIO_LINE_DIRECTION_IN; |
83 | ||
84 | return GPIO_LINE_DIRECTION_OUT; | |
6596e59e SM |
85 | } |
86 | ||
87 | static int exar_get_value(struct gpio_chip *chip, unsigned int offset) | |
88 | { | |
380b1e2f | 89 | struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); |
696868d0 BG |
90 | unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); |
91 | unsigned int bit = exar_offset_to_bit(exar_gpio, offset); | |
6596e59e | 92 | |
36fb7218 | 93 | return !!(regmap_test_bits(exar_gpio->regmap, addr, BIT(bit))); |
6596e59e SM |
94 | } |
95 | ||
96 | static void exar_set_value(struct gpio_chip *chip, unsigned int offset, | |
97 | int value) | |
98 | { | |
380b1e2f | 99 | struct exar_gpio_chip *exar_gpio = gpiochip_get_data(chip); |
696868d0 BG |
100 | unsigned int addr = exar_offset_to_lvl_addr(exar_gpio, offset); |
101 | unsigned int bit = exar_offset_to_bit(exar_gpio, offset); | |
6596e59e | 102 | |
36fb7218 BG |
103 | if (value) |
104 | regmap_set_bits(exar_gpio->regmap, addr, BIT(bit)); | |
105 | else | |
106 | regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit)); | |
6596e59e SM |
107 | } |
108 | ||
eddeae07 AL |
109 | static int exar_direction_output(struct gpio_chip *chip, unsigned int offset, |
110 | int value) | |
111 | { | |
36fb7218 BG |
112 | struct exar_gpio_chip *exar_gpio = gpiochip_get_data(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 | ||
eddeae07 | 116 | exar_set_value(chip, offset, value); |
36fb7218 BG |
117 | regmap_clear_bits(exar_gpio->regmap, addr, BIT(bit)); |
118 | ||
119 | return 0; | |
eddeae07 AL |
120 | } |
121 | ||
122 | static int exar_direction_input(struct gpio_chip *chip, unsigned int offset) | |
123 | { | |
36fb7218 BG |
124 | struct exar_gpio_chip *exar_gpio = gpiochip_get_data(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(exar_gpio->regmap, addr, BIT(bit)); | |
129 | ||
130 | return 0; | |
eddeae07 AL |
131 | } |
132 | ||
5300ebb6 BG |
133 | static void exar_devm_ida_free(void *data) |
134 | { | |
135 | struct exar_gpio_chip *exar_gpio = data; | |
136 | ||
137 | ida_free(&ida_index, exar_gpio->index); | |
138 | } | |
139 | ||
36fb7218 BG |
140 | static const struct regmap_config exar_regmap_config = { |
141 | .name = "exar-gpio", | |
142 | .reg_bits = 16, | |
143 | .val_bits = 8, | |
b4e83d36 | 144 | .io_port = true, |
36fb7218 BG |
145 | }; |
146 | ||
6596e59e SM |
147 | static int gpio_exar_probe(struct platform_device *pdev) |
148 | { | |
0c2c7e13 BG |
149 | struct device *dev = &pdev->dev; |
150 | struct pci_dev *pcidev = to_pci_dev(dev->parent); | |
6596e59e | 151 | struct exar_gpio_chip *exar_gpio; |
380b1e2f | 152 | u32 first_pin, ngpios; |
6596e59e SM |
153 | void __iomem *p; |
154 | int index, ret; | |
155 | ||
6596e59e | 156 | /* |
8847f5f9 JK |
157 | * The UART driver must have mapped region 0 prior to registering this |
158 | * device - use it. | |
6596e59e | 159 | */ |
8847f5f9 | 160 | p = pcim_iomap_table(pcidev)[0]; |
6596e59e SM |
161 | if (!p) |
162 | return -ENOMEM; | |
163 | ||
0c2c7e13 | 164 | ret = device_property_read_u32(dev, "exar,first-pin", &first_pin); |
380b1e2f JK |
165 | if (ret) |
166 | return ret; | |
167 | ||
0c2c7e13 | 168 | ret = device_property_read_u32(dev, "ngpios", &ngpios); |
380b1e2f JK |
169 | if (ret) |
170 | return ret; | |
171 | ||
0c2c7e13 | 172 | exar_gpio = devm_kzalloc(dev, sizeof(*exar_gpio), GFP_KERNEL); |
6596e59e SM |
173 | if (!exar_gpio) |
174 | return -ENOMEM; | |
175 | ||
5134272f QC |
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 | ||
36fb7218 BG |
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(exar_gpio->regmap)) | |
193 | return PTR_ERR(exar_gpio->regmap); | |
6596e59e | 194 | |
8e27c2ae | 195 | index = ida_alloc(&ida_index, GFP_KERNEL); |
36fb7218 BG |
196 | if (index < 0) |
197 | return index; | |
6596e59e | 198 | |
5300ebb6 BG |
199 | ret = devm_add_action_or_reset(dev, exar_devm_ida_free, exar_gpio); |
200 | if (ret) | |
201 | return ret; | |
202 | ||
6596e59e SM |
203 | sprintf(exar_gpio->name, "exar_gpio%d", index); |
204 | exar_gpio->gpio_chip.label = exar_gpio->name; | |
0c2c7e13 | 205 | exar_gpio->gpio_chip.parent = dev; |
6596e59e SM |
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; | |
380b1e2f | 212 | exar_gpio->gpio_chip.ngpio = ngpios; |
6596e59e | 213 | exar_gpio->index = index; |
380b1e2f | 214 | exar_gpio->first_pin = first_pin; |
6596e59e | 215 | |
0c2c7e13 | 216 | ret = devm_gpiochip_add_data(dev, &exar_gpio->gpio_chip, exar_gpio); |
6596e59e | 217 | if (ret) |
5300ebb6 | 218 | return ret; |
6596e59e | 219 | |
6596e59e SM |
220 | return 0; |
221 | } | |
222 | ||
223 | static struct platform_driver gpio_exar_driver = { | |
224 | .probe = gpio_exar_probe, | |
6596e59e SM |
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 <[email protected]>"); | |
235 | MODULE_LICENSE("GPL"); |