Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2020, Broadcom */
0003 
0004 #include <linux/init.h>
0005 #include <linux/types.h>
0006 #include <linux/module.h>
0007 #include <linux/platform_device.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/io.h>
0010 #include <linux/device.h>
0011 #include <linux/of.h>
0012 #include <linux/kernel.h>
0013 #include <linux/kdebug.h>
0014 #include <linux/gpio/consumer.h>
0015 
0016 struct out_pin {
0017     u32 enable_mask;
0018     u32 value_mask;
0019     u32 changed_mask;
0020     u32 clr_changed_mask;
0021     struct gpio_desc *gpiod;
0022     const char *name;
0023 };
0024 
0025 struct in_pin {
0026     u32 enable_mask;
0027     u32 value_mask;
0028     struct gpio_desc *gpiod;
0029     const char *name;
0030     struct brcmstb_usb_pinmap_data *pdata;
0031 };
0032 
0033 struct brcmstb_usb_pinmap_data {
0034     void __iomem *regs;
0035     int in_count;
0036     struct in_pin *in_pins;
0037     int out_count;
0038     struct out_pin *out_pins;
0039 };
0040 
0041 
0042 static void pinmap_set(void __iomem *reg, u32 mask)
0043 {
0044     u32 val;
0045 
0046     val = readl(reg);
0047     val |= mask;
0048     writel(val, reg);
0049 }
0050 
0051 static void pinmap_unset(void __iomem *reg, u32 mask)
0052 {
0053     u32 val;
0054 
0055     val = readl(reg);
0056     val &= ~mask;
0057     writel(val, reg);
0058 }
0059 
0060 static void sync_in_pin(struct in_pin *pin)
0061 {
0062     u32 val;
0063 
0064     val = gpiod_get_value(pin->gpiod);
0065     if (val)
0066         pinmap_set(pin->pdata->regs, pin->value_mask);
0067     else
0068         pinmap_unset(pin->pdata->regs, pin->value_mask);
0069 }
0070 
0071 /*
0072  * Interrupt from override register, propagate from override bit
0073  * to GPIO.
0074  */
0075 static irqreturn_t brcmstb_usb_pinmap_ovr_isr(int irq, void *dev_id)
0076 {
0077     struct brcmstb_usb_pinmap_data *pdata = dev_id;
0078     struct out_pin *pout;
0079     u32 val;
0080     u32 bit;
0081     int x;
0082 
0083     pr_debug("%s: reg: 0x%x\n", __func__, readl(pdata->regs));
0084     pout = pdata->out_pins;
0085     for (x = 0; x < pdata->out_count; x++) {
0086         val = readl(pdata->regs);
0087         if (val & pout->changed_mask) {
0088             pinmap_set(pdata->regs, pout->clr_changed_mask);
0089             pinmap_unset(pdata->regs, pout->clr_changed_mask);
0090             bit = val & pout->value_mask;
0091             gpiod_set_value(pout->gpiod, bit ? 1 : 0);
0092             pr_debug("%s: %s bit changed state to %d\n",
0093                  __func__, pout->name, bit ? 1 : 0);
0094         }
0095     }
0096     return IRQ_HANDLED;
0097 }
0098 
0099 /*
0100  * Interrupt from GPIO, propagate from GPIO to override bit.
0101  */
0102 static irqreturn_t brcmstb_usb_pinmap_gpio_isr(int irq, void *dev_id)
0103 {
0104     struct in_pin *pin = dev_id;
0105 
0106     pr_debug("%s: %s pin changed state\n", __func__, pin->name);
0107     sync_in_pin(pin);
0108     return IRQ_HANDLED;
0109 }
0110 
0111 
0112 static void get_pin_counts(struct device_node *dn, int *in_count,
0113                int *out_count)
0114 {
0115     int in;
0116     int out;
0117 
0118     *in_count = 0;
0119     *out_count = 0;
0120     in = of_property_count_strings(dn, "brcm,in-functions");
0121     if (in < 0)
0122         return;
0123     out = of_property_count_strings(dn, "brcm,out-functions");
0124     if (out < 0)
0125         return;
0126     *in_count = in;
0127     *out_count = out;
0128 }
0129 
0130 static int parse_pins(struct device *dev, struct device_node *dn,
0131               struct brcmstb_usb_pinmap_data *pdata)
0132 {
0133     struct out_pin *pout;
0134     struct in_pin *pin;
0135     int index;
0136     int res;
0137     int x;
0138 
0139     pin = pdata->in_pins;
0140     for (x = 0, index = 0; x < pdata->in_count; x++) {
0141         pin->gpiod = devm_gpiod_get_index(dev, "in", x, GPIOD_IN);
0142         if (IS_ERR(pin->gpiod)) {
0143             dev_err(dev, "Error getting gpio %s\n", pin->name);
0144             return PTR_ERR(pin->gpiod);
0145 
0146         }
0147         res = of_property_read_string_index(dn, "brcm,in-functions", x,
0148                             &pin->name);
0149         if (res < 0) {
0150             dev_err(dev, "Error getting brcm,in-functions for %s\n",
0151                 pin->name);
0152             return res;
0153         }
0154         res = of_property_read_u32_index(dn, "brcm,in-masks", index++,
0155                          &pin->enable_mask);
0156         if (res < 0) {
0157             dev_err(dev, "Error getting 1st brcm,in-masks for %s\n",
0158                 pin->name);
0159             return res;
0160         }
0161         res = of_property_read_u32_index(dn, "brcm,in-masks", index++,
0162                          &pin->value_mask);
0163         if (res < 0) {
0164             dev_err(dev, "Error getting 2nd brcm,in-masks for %s\n",
0165                 pin->name);
0166             return res;
0167         }
0168         pin->pdata = pdata;
0169         pin++;
0170     }
0171     pout = pdata->out_pins;
0172     for (x = 0, index = 0; x < pdata->out_count; x++) {
0173         pout->gpiod = devm_gpiod_get_index(dev, "out", x,
0174                            GPIOD_OUT_HIGH);
0175         if (IS_ERR(pout->gpiod)) {
0176             dev_err(dev, "Error getting gpio %s\n", pin->name);
0177             return PTR_ERR(pout->gpiod);
0178         }
0179         res = of_property_read_string_index(dn, "brcm,out-functions", x,
0180                             &pout->name);
0181         if (res < 0) {
0182             dev_err(dev, "Error getting brcm,out-functions for %s\n",
0183                 pout->name);
0184             return res;
0185         }
0186         res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
0187                          &pout->enable_mask);
0188         if (res < 0) {
0189             dev_err(dev, "Error getting 1st brcm,out-masks for %s\n",
0190                 pout->name);
0191             return res;
0192         }
0193         res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
0194                          &pout->value_mask);
0195         if (res < 0) {
0196             dev_err(dev, "Error getting 2nd brcm,out-masks for %s\n",
0197                 pout->name);
0198             return res;
0199         }
0200         res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
0201                          &pout->changed_mask);
0202         if (res < 0) {
0203             dev_err(dev, "Error getting 3rd brcm,out-masks for %s\n",
0204                 pout->name);
0205             return res;
0206         }
0207         res = of_property_read_u32_index(dn, "brcm,out-masks", index++,
0208                          &pout->clr_changed_mask);
0209         if (res < 0) {
0210             dev_err(dev, "Error getting 4th out-masks for %s\n",
0211                 pout->name);
0212             return res;
0213         }
0214         pout++;
0215     }
0216     return 0;
0217 }
0218 
0219 static void sync_all_pins(struct brcmstb_usb_pinmap_data *pdata)
0220 {
0221     struct out_pin *pout;
0222     struct in_pin *pin;
0223     int val;
0224     int x;
0225 
0226     /*
0227      * Enable the override, clear any changed condition and
0228      * propagate the state to the GPIO for all out pins.
0229      */
0230     pout = pdata->out_pins;
0231     for (x = 0; x < pdata->out_count; x++) {
0232         pinmap_set(pdata->regs, pout->enable_mask);
0233         pinmap_set(pdata->regs, pout->clr_changed_mask);
0234         pinmap_unset(pdata->regs, pout->clr_changed_mask);
0235         val = readl(pdata->regs) & pout->value_mask;
0236         gpiod_set_value(pout->gpiod, val ? 1 : 0);
0237         pout++;
0238     }
0239 
0240     /* sync and enable all in pins. */
0241     pin = pdata->in_pins;
0242     for (x = 0; x < pdata->in_count; x++) {
0243         sync_in_pin(pin);
0244         pinmap_set(pdata->regs, pin->enable_mask);
0245         pin++;
0246     }
0247 }
0248 
0249 static int __init brcmstb_usb_pinmap_probe(struct platform_device *pdev)
0250 {
0251     struct device_node *dn = pdev->dev.of_node;
0252     struct brcmstb_usb_pinmap_data *pdata;
0253     struct in_pin *pin;
0254     struct resource *r;
0255     int out_count;
0256     int in_count;
0257     int err;
0258     int irq;
0259     int x;
0260 
0261     get_pin_counts(dn, &in_count, &out_count);
0262     if ((in_count + out_count) == 0)
0263         return -EINVAL;
0264 
0265     r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0266     if (!r)
0267         return -EINVAL;
0268 
0269     pdata = devm_kzalloc(&pdev->dev,
0270                  sizeof(*pdata) +
0271                  (sizeof(struct in_pin) * in_count) +
0272                  (sizeof(struct out_pin) * out_count), GFP_KERNEL);
0273     if (!pdata)
0274         return -ENOMEM;
0275 
0276     pdata->in_count = in_count;
0277     pdata->out_count = out_count;
0278     pdata->in_pins = (struct in_pin *)(pdata + 1);
0279     pdata->out_pins = (struct out_pin *)(pdata->in_pins + in_count);
0280 
0281     pdata->regs = devm_ioremap(&pdev->dev, r->start, resource_size(r));
0282     if (!pdata->regs)
0283         return -ENOMEM;
0284     platform_set_drvdata(pdev, pdata);
0285 
0286     err = parse_pins(&pdev->dev, dn, pdata);
0287     if (err)
0288         return err;
0289 
0290     sync_all_pins(pdata);
0291 
0292     if (out_count) {
0293 
0294         /* Enable interrupt for out pins */
0295         irq = platform_get_irq(pdev, 0);
0296         if (irq < 0)
0297             return irq;
0298         err = devm_request_irq(&pdev->dev, irq,
0299                        brcmstb_usb_pinmap_ovr_isr,
0300                        IRQF_TRIGGER_RISING,
0301                        pdev->name, pdata);
0302         if (err < 0) {
0303             dev_err(&pdev->dev, "Error requesting IRQ\n");
0304             return err;
0305         }
0306     }
0307 
0308     for (x = 0, pin = pdata->in_pins; x < pdata->in_count; x++, pin++) {
0309         irq = gpiod_to_irq(pin->gpiod);
0310         if (irq < 0) {
0311             dev_err(&pdev->dev, "Error getting IRQ for %s pin\n",
0312                 pin->name);
0313             return irq;
0314         }
0315         err = devm_request_irq(&pdev->dev, irq,
0316                        brcmstb_usb_pinmap_gpio_isr,
0317                        IRQF_SHARED | IRQF_TRIGGER_RISING |
0318                        IRQF_TRIGGER_FALLING,
0319                        pdev->name, pin);
0320         if (err < 0) {
0321             dev_err(&pdev->dev, "Error requesting IRQ for %s pin\n",
0322                 pin->name);
0323             return err;
0324         }
0325     }
0326 
0327     dev_dbg(&pdev->dev, "Driver probe succeeded\n");
0328     dev_dbg(&pdev->dev, "In pin count: %d, out pin count: %d\n",
0329         pdata->in_count, pdata->out_count);
0330     return 0;
0331 }
0332 
0333 
0334 static const struct of_device_id brcmstb_usb_pinmap_of_match[] = {
0335     { .compatible = "brcm,usb-pinmap" },
0336     { },
0337 };
0338 
0339 static struct platform_driver brcmstb_usb_pinmap_driver = {
0340     .driver = {
0341         .name   = "brcm-usb-pinmap",
0342         .of_match_table = brcmstb_usb_pinmap_of_match,
0343     },
0344 };
0345 
0346 static int __init brcmstb_usb_pinmap_init(void)
0347 {
0348     return platform_driver_probe(&brcmstb_usb_pinmap_driver,
0349                      brcmstb_usb_pinmap_probe);
0350 }
0351 
0352 module_init(brcmstb_usb_pinmap_init);
0353 MODULE_AUTHOR("Al Cooper <alcooperx@gmail.com>");
0354 MODULE_DESCRIPTION("Broadcom USB Pinmap Driver");
0355 MODULE_LICENSE("GPL");