1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2020, Broadcom */ 3 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> 9 #include <linux/io.h> 10 #include <linux/device.h> 11 #include <linux/of.h> 12 #include <linux/kernel.h> 13 #include <linux/kdebug.h> 14 #include <linux/gpio/consumer.h> 15 16 struct out_pin { 17 u32 enable_mask; 18 u32 value_mask; 19 u32 changed_mask; 20 u32 clr_changed_mask; 21 struct gpio_desc *gpiod; 22 const char *name; 23 }; 24 25 struct in_pin { 26 u32 enable_mask; 27 u32 value_mask; 28 struct gpio_desc *gpiod; 29 const char *name; 30 struct brcmstb_usb_pinmap_data *pdata; 31 }; 32 33 struct brcmstb_usb_pinmap_data { 34 void __iomem *regs; 35 int in_count; 36 struct in_pin *in_pins; 37 int out_count; 38 struct out_pin *out_pins; 39 }; 40 41 42 static void pinmap_set(void __iomem *reg, u32 mask) 43 { 44 u32 val; 45 46 val = readl(reg); 47 val |= mask; 48 writel(val, reg); 49 } 50 51 static void pinmap_unset(void __iomem *reg, u32 mask) 52 { 53 u32 val; 54 55 val = readl(reg); 56 val &= ~mask; 57 writel(val, reg); 58 } 59 60 static void sync_in_pin(struct in_pin *pin) 61 { 62 u32 val; 63 64 val = gpiod_get_value(pin->gpiod); 65 if (val) 66 pinmap_set(pin->pdata->regs, pin->value_mask); 67 else 68 pinmap_unset(pin->pdata->regs, pin->value_mask); 69 } 70 71 /* 72 * Interrupt from override register, propagate from override bit 73 * to GPIO. 74 */ 75 static irqreturn_t brcmstb_usb_pinmap_ovr_isr(int irq, void *dev_id) 76 { 77 struct brcmstb_usb_pinmap_data *pdata = dev_id; 78 struct out_pin *pout; 79 u32 val; 80 u32 bit; 81 int x; 82 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); 94 } 95 } 96 return IRQ_HANDLED; 97 } 98 99 /* 100 * Interrupt from GPIO, propagate from GPIO to override bit. 101 */ 102 static irqreturn_t brcmstb_usb_pinmap_gpio_isr(int irq, void *dev_id) 103 { 104 struct in_pin *pin = dev_id; 105 106 pr_debug("%s: %s pin changed state\n", __func__, pin->name); 107 sync_in_pin(pin); 108 return IRQ_HANDLED; 109 } 110 111 112 static void get_pin_counts(struct device_node *dn, int *in_count, 113 int *out_count) 114 { 115 int in; 116 int out; 117 118 *in_count = 0; 119 *out_count = 0; 120 in = of_property_count_strings(dn, "brcm,in-functions"); 121 if (in < 0) 122 return; 123 out = of_property_count_strings(dn, "brcm,out-functions"); 124 if (out < 0) 125 return; 126 *in_count = in; 127 *out_count = out; 128 } 129 130 static int parse_pins(struct device *dev, struct device_node *dn, 131 struct brcmstb_usb_pinmap_data *pdata) 132 { 133 struct out_pin *pout; 134 struct in_pin *pin; 135 int index; 136 int res; 137 int x; 138 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); 145 146 } 147 res = of_property_read_string_index(dn, "brcm,in-functions", x, 148 &pin->name); 149 if (res < 0) { 150 dev_err(dev, "Error getting brcm,in-functions for %s\n", 151 pin->name); 152 return res; 153 } 154 res = of_property_read_u32_index(dn, "brcm,in-masks", index++, 155 &pin->enable_mask); 156 if (res < 0) { 157 dev_err(dev, "Error getting 1st brcm,in-masks for %s\n", 158 pin->name); 159 return res; 160 } 161 res = of_property_read_u32_index(dn, "brcm,in-masks", index++, 162 &pin->value_mask); 163 if (res < 0) { 164 dev_err(dev, "Error getting 2nd brcm,in-masks for %s\n", 165 pin->name); 166 return res; 167 } 168 pin->pdata = pdata; 169 pin++; 170 } 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, 174 GPIOD_OUT_HIGH); 175 if (IS_ERR(pout->gpiod)) { 176 dev_err(dev, "Error getting gpio %s\n", pin->name); 177 return PTR_ERR(pout->gpiod); 178 } 179 res = of_property_read_string_index(dn, "brcm,out-functions", x, 180 &pout->name); 181 if (res < 0) { 182 dev_err(dev, "Error getting brcm,out-functions for %s\n", 183 pout->name); 184 return res; 185 } 186 res = of_property_read_u32_index(dn, "brcm,out-masks", index++, 187 &pout->enable_mask); 188 if (res < 0) { 189 dev_err(dev, "Error getting 1st brcm,out-masks for %s\n", 190 pout->name); 191 return res; 192 } 193 res = of_property_read_u32_index(dn, "brcm,out-masks", index++, 194 &pout->value_mask); 195 if (res < 0) { 196 dev_err(dev, "Error getting 2nd brcm,out-masks for %s\n", 197 pout->name); 198 return res; 199 } 200 res = of_property_read_u32_index(dn, "brcm,out-masks", index++, 201 &pout->changed_mask); 202 if (res < 0) { 203 dev_err(dev, "Error getting 3rd brcm,out-masks for %s\n", 204 pout->name); 205 return res; 206 } 207 res = of_property_read_u32_index(dn, "brcm,out-masks", index++, 208 &pout->clr_changed_mask); 209 if (res < 0) { 210 dev_err(dev, "Error getting 4th out-masks for %s\n", 211 pout->name); 212 return res; 213 } 214 pout++; 215 } 216 return 0; 217 } 218 219 static void sync_all_pins(struct brcmstb_usb_pinmap_data *pdata) 220 { 221 struct out_pin *pout; 222 struct in_pin *pin; 223 int val; 224 int x; 225 226 /* 227 * Enable the override, clear any changed condition and 228 * propagate the state to the GPIO for all out pins. 229 */ 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); 237 pout++; 238 } 239 240 /* sync and enable all in pins. */ 241 pin = pdata->in_pins; 242 for (x = 0; x < pdata->in_count; x++) { 243 sync_in_pin(pin); 244 pinmap_set(pdata->regs, pin->enable_mask); 245 pin++; 246 } 247 } 248 249 static int __init brcmstb_usb_pinmap_probe(struct platform_device *pdev) 250 { 251 struct device_node *dn = pdev->dev.of_node; 252 struct brcmstb_usb_pinmap_data *pdata; 253 struct in_pin *pin; 254 struct resource *r; 255 int out_count; 256 int in_count; 257 int err; 258 int irq; 259 int x; 260 261 get_pin_counts(dn, &in_count, &out_count); 262 if ((in_count + out_count) == 0) 263 return -EINVAL; 264 265 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 266 267 pdata = devm_kzalloc(&pdev->dev, 268 sizeof(*pdata) + 269 (sizeof(struct in_pin) * in_count) + 270 (sizeof(struct out_pin) * out_count), GFP_KERNEL); 271 if (!pdata) 272 return -ENOMEM; 273 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); 278 279 pdata->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r)); 280 if (!pdata->regs) 281 return -ENOMEM; 282 platform_set_drvdata(pdev, pdata); 283 284 err = parse_pins(&pdev->dev, dn, pdata); 285 if (err) 286 return err; 287 288 sync_all_pins(pdata); 289 290 if (out_count) { 291 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, 296 IRQF_TRIGGER_RISING, 297 pdev->name, pdata); 298 if (err < 0) { 299 dev_err(&pdev->dev, "Error requesting IRQ\n"); 300 return err; 301 } 302 } 303 304 for (x = 0, pin = pdata->in_pins; x < pdata->in_count; x++, pin++) { 305 irq = gpiod_to_irq(pin->gpiod); 306 if (irq < 0) { 307 dev_err(&pdev->dev, "Error getting IRQ for %s pin\n", 308 pin->name); 309 return irq; 310 } 311 err = devm_request_irq(&pdev->dev, irq, 312 brcmstb_usb_pinmap_gpio_isr, 313 IRQF_SHARED | IRQF_TRIGGER_RISING | 314 IRQF_TRIGGER_FALLING, 315 pdev->name, pin); 316 if (err < 0) { 317 dev_err(&pdev->dev, "Error requesting IRQ for %s pin\n", 318 pin->name); 319 return err; 320 } 321 } 322 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); 326 return 0; 327 } 328 329 330 static const struct of_device_id brcmstb_usb_pinmap_of_match[] = { 331 { .compatible = "brcm,usb-pinmap" }, 332 { }, 333 }; 334 335 static struct platform_driver brcmstb_usb_pinmap_driver = { 336 .driver = { 337 .name = "brcm-usb-pinmap", 338 .of_match_table = brcmstb_usb_pinmap_of_match, 339 }, 340 }; 341 342 static int __init brcmstb_usb_pinmap_init(void) 343 { 344 return platform_driver_probe(&brcmstb_usb_pinmap_driver, 345 brcmstb_usb_pinmap_probe); 346 } 347 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"); 352