1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020, Broadcom */
4 #include <linux/init.h>
5 #include <linux/types.h>
6 #include <linux/module.h>
7 #include <linux/platform_device.h>
8 #include <linux/interrupt.h>
10 #include <linux/device.h>
12 #include <linux/kernel.h>
13 #include <linux/kdebug.h>
14 #include <linux/gpio/consumer.h>
21 struct gpio_desc *gpiod;
28 struct gpio_desc *gpiod;
30 struct brcmstb_usb_pinmap_data *pdata;
33 struct brcmstb_usb_pinmap_data {
36 struct in_pin *in_pins;
38 struct out_pin *out_pins;
42 static void pinmap_set(void __iomem *reg, u32 mask)
51 static void pinmap_unset(void __iomem *reg, u32 mask)
60 static void sync_in_pin(struct in_pin *pin)
64 val = gpiod_get_value(pin->gpiod);
66 pinmap_set(pin->pdata->regs, pin->value_mask);
68 pinmap_unset(pin->pdata->regs, pin->value_mask);
72 * Interrupt from override register, propagate from override bit
75 static irqreturn_t brcmstb_usb_pinmap_ovr_isr(int irq, void *dev_id)
77 struct brcmstb_usb_pinmap_data *pdata = dev_id;
83 pr_debug("%s: reg: 0x%x\n", __func__, readl(pdata->regs));
84 pout = pdata->out_pins;
85 for (x = 0; x < pdata->out_count; x++) {
86 val = readl(pdata->regs);
87 if (val & pout->changed_mask) {
88 pinmap_set(pdata->regs, pout->clr_changed_mask);
89 pinmap_unset(pdata->regs, pout->clr_changed_mask);
90 bit = val & pout->value_mask;
91 gpiod_set_value(pout->gpiod, bit ? 1 : 0);
92 pr_debug("%s: %s bit changed state to %d\n",
93 __func__, pout->name, bit ? 1 : 0);
100 * Interrupt from GPIO, propagate from GPIO to override bit.
102 static irqreturn_t brcmstb_usb_pinmap_gpio_isr(int irq, void *dev_id)
104 struct in_pin *pin = dev_id;
106 pr_debug("%s: %s pin changed state\n", __func__, pin->name);
112 static void get_pin_counts(struct device_node *dn, int *in_count,
120 in = of_property_count_strings(dn, "brcm,in-functions");
123 out = of_property_count_strings(dn, "brcm,out-functions");
130 static int parse_pins(struct device *dev, struct device_node *dn,
131 struct brcmstb_usb_pinmap_data *pdata)
133 struct out_pin *pout;
139 pin = pdata->in_pins;
140 for (x = 0, index = 0; x < pdata->in_count; x++) {
141 pin->gpiod = devm_gpiod_get_index(dev, "in", x, GPIOD_IN);
142 if (IS_ERR(pin->gpiod)) {
143 dev_err(dev, "Error getting gpio %s\n", pin->name);
144 return PTR_ERR(pin->gpiod);
147 res = of_property_read_string_index(dn, "brcm,in-functions", x,
150 dev_err(dev, "Error getting brcm,in-functions for %s\n",
154 res = of_property_read_u32_index(dn, "brcm,in-masks", index++,
157 dev_err(dev, "Error getting 1st brcm,in-masks for %s\n",
161 res = of_property_read_u32_index(dn, "brcm,in-masks", index++,
164 dev_err(dev, "Error getting 2nd brcm,in-masks for %s\n",
171 pout = pdata->out_pins;
172 for (x = 0, index = 0; x < pdata->out_count; x++) {
173 pout->gpiod = devm_gpiod_get_index(dev, "out", x,
175 if (IS_ERR(pout->gpiod)) {
176 dev_err(dev, "Error getting gpio %s\n", pin->name);
177 return PTR_ERR(pout->gpiod);
179 res = of_property_read_string_index(dn, "brcm,out-functions", x,
182 dev_err(dev, "Error getting brcm,out-functions for %s\n",
186 res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
189 dev_err(dev, "Error getting 1st brcm,out-masks for %s\n",
193 res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
196 dev_err(dev, "Error getting 2nd brcm,out-masks for %s\n",
200 res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
201 &pout->changed_mask);
203 dev_err(dev, "Error getting 3rd brcm,out-masks for %s\n",
207 res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
208 &pout->clr_changed_mask);
210 dev_err(dev, "Error getting 4th out-masks for %s\n",
219 static void sync_all_pins(struct brcmstb_usb_pinmap_data *pdata)
221 struct out_pin *pout;
227 * Enable the override, clear any changed condition and
228 * propagate the state to the GPIO for all out pins.
230 pout = pdata->out_pins;
231 for (x = 0; x < pdata->out_count; x++) {
232 pinmap_set(pdata->regs, pout->enable_mask);
233 pinmap_set(pdata->regs, pout->clr_changed_mask);
234 pinmap_unset(pdata->regs, pout->clr_changed_mask);
235 val = readl(pdata->regs) & pout->value_mask;
236 gpiod_set_value(pout->gpiod, val ? 1 : 0);
240 /* sync and enable all in pins. */
241 pin = pdata->in_pins;
242 for (x = 0; x < pdata->in_count; x++) {
244 pinmap_set(pdata->regs, pin->enable_mask);
249 static int __init brcmstb_usb_pinmap_probe(struct platform_device *pdev)
251 struct device_node *dn = pdev->dev.of_node;
252 struct brcmstb_usb_pinmap_data *pdata;
261 get_pin_counts(dn, &in_count, &out_count);
262 if ((in_count + out_count) == 0)
265 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
269 pdata = devm_kzalloc(&pdev->dev,
271 (sizeof(struct in_pin) * in_count) +
272 (sizeof(struct out_pin) * out_count), GFP_KERNEL);
276 pdata->in_count = in_count;
277 pdata->out_count = out_count;
278 pdata->in_pins = (struct in_pin *)(pdata + 1);
279 pdata->out_pins = (struct out_pin *)(pdata->in_pins + in_count);
281 pdata->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
284 platform_set_drvdata(pdev, pdata);
286 err = parse_pins(&pdev->dev, dn, pdata);
290 sync_all_pins(pdata);
294 /* Enable interrupt for out pins */
295 irq = platform_get_irq(pdev, 0);
296 err = devm_request_irq(&pdev->dev, irq,
297 brcmstb_usb_pinmap_ovr_isr,
301 dev_err(&pdev->dev, "Error requesting IRQ\n");
306 for (x = 0, pin = pdata->in_pins; x < pdata->in_count; x++, pin++) {
307 irq = gpiod_to_irq(pin->gpiod);
309 dev_err(&pdev->dev, "Error getting IRQ for %s pin\n",
313 err = devm_request_irq(&pdev->dev, irq,
314 brcmstb_usb_pinmap_gpio_isr,
315 IRQF_SHARED | IRQF_TRIGGER_RISING |
316 IRQF_TRIGGER_FALLING,
319 dev_err(&pdev->dev, "Error requesting IRQ for %s pin\n",
325 dev_dbg(&pdev->dev, "Driver probe succeeded\n");
326 dev_dbg(&pdev->dev, "In pin count: %d, out pin count: %d\n",
327 pdata->in_count, pdata->out_count);
332 static const struct of_device_id brcmstb_usb_pinmap_of_match[] = {
333 { .compatible = "brcm,usb-pinmap" },
337 static struct platform_driver brcmstb_usb_pinmap_driver = {
339 .name = "brcm-usb-pinmap",
340 .of_match_table = brcmstb_usb_pinmap_of_match,
344 static int __init brcmstb_usb_pinmap_init(void)
346 return platform_driver_probe(&brcmstb_usb_pinmap_driver,
347 brcmstb_usb_pinmap_probe);
350 module_init(brcmstb_usb_pinmap_init);
352 MODULE_DESCRIPTION("Broadcom USB Pinmap Driver");
353 MODULE_LICENSE("GPL");