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);
267 pdata
= devm_kzalloc(&pdev
->dev
,
269 (sizeof(struct in_pin
) * in_count
) +
270 (sizeof(struct out_pin
) * out_count
), GFP_KERNEL
);
274 pdata
->in_count
= in_count
;
275 pdata
->out_count
= out_count
;
276 pdata
->in_pins
= (struct in_pin
*)(pdata
+ 1);
277 pdata
->out_pins
= (struct out_pin
*)(pdata
->in_pins
+ in_count
);
279 pdata
->regs
= devm_ioremap(&pdev
->dev
, r
->start
, resource_size(r
));
282 platform_set_drvdata(pdev
, pdata
);
284 err
= parse_pins(&pdev
->dev
, dn
, pdata
);
288 sync_all_pins(pdata
);
292 /* Enable interrupt for out pins */
293 irq
= platform_get_irq(pdev
, 0);
294 err
= devm_request_irq(&pdev
->dev
, irq
,
295 brcmstb_usb_pinmap_ovr_isr
,
299 dev_err(&pdev
->dev
, "Error requesting IRQ\n");
304 for (x
= 0, pin
= pdata
->in_pins
; x
< pdata
->in_count
; x
++, pin
++) {
305 irq
= gpiod_to_irq(pin
->gpiod
);
307 dev_err(&pdev
->dev
, "Error getting IRQ for %s pin\n",
311 err
= devm_request_irq(&pdev
->dev
, irq
,
312 brcmstb_usb_pinmap_gpio_isr
,
313 IRQF_SHARED
| IRQF_TRIGGER_RISING
|
314 IRQF_TRIGGER_FALLING
,
317 dev_err(&pdev
->dev
, "Error requesting IRQ for %s pin\n",
323 dev_dbg(&pdev
->dev
, "Driver probe succeeded\n");
324 dev_dbg(&pdev
->dev
, "In pin count: %d, out pin count: %d\n",
325 pdata
->in_count
, pdata
->out_count
);
330 static const struct of_device_id brcmstb_usb_pinmap_of_match
[] = {
331 { .compatible
= "brcm,usb-pinmap" },
335 static struct platform_driver brcmstb_usb_pinmap_driver
= {
337 .name
= "brcm-usb-pinmap",
338 .of_match_table
= brcmstb_usb_pinmap_of_match
,
342 static int __init
brcmstb_usb_pinmap_init(void)
344 return platform_driver_probe(&brcmstb_usb_pinmap_driver
,
345 brcmstb_usb_pinmap_probe
);
348 module_init(brcmstb_usb_pinmap_init
);
349 MODULE_AUTHOR("Al Cooper <alcooperx@gmail.com>");
350 MODULE_DESCRIPTION("Broadcom USB Pinmap Driver");
351 MODULE_LICENSE("GPL");