0001
0002
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
0073
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
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
0228
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
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
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");