diff options
author | Nathan Williams <nathan@traverse.com.au> | 2012-12-19 06:01:18 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-19 17:53:53 -0500 |
commit | f9baad02e7411d9f38d5ebe1a1cdcde4ceec100d (patch) | |
tree | 298ecb3ed8aa77d1b7fb9b1a5677d675abb60fa9 /drivers/atm/solos-pci.c | |
parent | 83c34fd00d0c3989466e95808bf12af9bf87e383 (diff) |
solos-pci: add GPIO support for newer versions on Geos board
dwmw2: Tidy up a little, simpler matching on which GPIO is being accessed,
only register on newer boards, register under PCI device instead of
duplicating them under each ATM device.
Signed-off-by: Nathan Williams <nathan@traverse.com.au>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/atm/solos-pci.c')
-rw-r--r-- | drivers/atm/solos-pci.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index c909b7b7d5f1..473d80878ec9 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #define FLASH_BUSY 0x60 | 56 | #define FLASH_BUSY 0x60 |
57 | #define FPGA_MODE 0x5C | 57 | #define FPGA_MODE 0x5C |
58 | #define FLASH_MODE 0x58 | 58 | #define FLASH_MODE 0x58 |
59 | #define GPIO_STATUS 0x54 | ||
59 | #define TX_DMA_ADDR(port) (0x40 + (4 * (port))) | 60 | #define TX_DMA_ADDR(port) (0x40 + (4 * (port))) |
60 | #define RX_DMA_ADDR(port) (0x30 + (4 * (port))) | 61 | #define RX_DMA_ADDR(port) (0x30 + (4 * (port))) |
61 | 62 | ||
@@ -498,6 +499,78 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr, | |||
498 | return err?:count; | 499 | return err?:count; |
499 | } | 500 | } |
500 | 501 | ||
502 | struct geos_gpio_attr { | ||
503 | struct device_attribute attr; | ||
504 | int offset; | ||
505 | }; | ||
506 | |||
507 | #define SOLOS_GPIO_ATTR(_name, _mode, _show, _store, _offset) \ | ||
508 | struct geos_gpio_attr gpio_attr_##_name = { \ | ||
509 | .attr = __ATTR(_name, _mode, _show, _store), \ | ||
510 | .offset = _offset } | ||
511 | |||
512 | static ssize_t geos_gpio_store(struct device *dev, struct device_attribute *attr, | ||
513 | const char *buf, size_t count) | ||
514 | { | ||
515 | struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); | ||
516 | struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); | ||
517 | struct solos_card *card = pci_get_drvdata(pdev); | ||
518 | uint32_t data32; | ||
519 | |||
520 | if (count != 1 && (count != 2 || buf[1] != '\n')) | ||
521 | return -EINVAL; | ||
522 | |||
523 | spin_lock_irq(&card->param_queue_lock); | ||
524 | data32 = ioread32(card->config_regs + GPIO_STATUS); | ||
525 | if (buf[0] == '1') { | ||
526 | data32 |= 1 << gattr->offset; | ||
527 | iowrite32(data32, card->config_regs + GPIO_STATUS); | ||
528 | } else if (buf[0] == '0') { | ||
529 | data32 &= ~(1 << gattr->offset); | ||
530 | iowrite32(data32, card->config_regs + GPIO_STATUS); | ||
531 | } else { | ||
532 | count = -EINVAL; | ||
533 | } | ||
534 | spin_lock_irq(&card->param_queue_lock); | ||
535 | return count; | ||
536 | } | ||
537 | |||
538 | static ssize_t geos_gpio_show(struct device *dev, struct device_attribute *attr, | ||
539 | char *buf) | ||
540 | { | ||
541 | struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); | ||
542 | struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); | ||
543 | struct solos_card *card = pci_get_drvdata(pdev); | ||
544 | uint32_t data32; | ||
545 | |||
546 | data32 = ioread32(card->config_regs + GPIO_STATUS); | ||
547 | data32 = (data32 >> gattr->offset) & 1; | ||
548 | |||
549 | return sprintf(buf, "%d\n", data32); | ||
550 | } | ||
551 | |||
552 | static ssize_t hardware_show(struct device *dev, struct device_attribute *attr, | ||
553 | char *buf) | ||
554 | { | ||
555 | struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); | ||
556 | struct geos_gpio_attr *gattr = container_of(attr, struct geos_gpio_attr, attr); | ||
557 | struct solos_card *card = pci_get_drvdata(pdev); | ||
558 | uint32_t data32; | ||
559 | |||
560 | data32 = ioread32(card->config_regs + GPIO_STATUS); | ||
561 | switch (gattr->offset) { | ||
562 | case 0: | ||
563 | /* HardwareVersion */ | ||
564 | data32 = data32 & 0x1F; | ||
565 | break; | ||
566 | case 1: | ||
567 | /* HardwareVariant */ | ||
568 | data32 = (data32 >> 5) & 0x0F; | ||
569 | break; | ||
570 | } | ||
571 | return sprintf(buf, "%d\n", data32); | ||
572 | } | ||
573 | |||
501 | static DEVICE_ATTR(console, 0644, console_show, console_store); | 574 | static DEVICE_ATTR(console, 0644, console_show, console_store); |
502 | 575 | ||
503 | 576 | ||
@@ -506,6 +579,14 @@ static DEVICE_ATTR(console, 0644, console_show, console_store); | |||
506 | 579 | ||
507 | #include "solos-attrlist.c" | 580 | #include "solos-attrlist.c" |
508 | 581 | ||
582 | static SOLOS_GPIO_ATTR(GPIO1, 0644, geos_gpio_show, geos_gpio_store, 9); | ||
583 | static SOLOS_GPIO_ATTR(GPIO2, 0644, geos_gpio_show, geos_gpio_store, 10); | ||
584 | static SOLOS_GPIO_ATTR(GPIO3, 0644, geos_gpio_show, geos_gpio_store, 11); | ||
585 | static SOLOS_GPIO_ATTR(GPIO4, 0644, geos_gpio_show, geos_gpio_store, 12); | ||
586 | static SOLOS_GPIO_ATTR(GPIO5, 0644, geos_gpio_show, geos_gpio_store, 13); | ||
587 | static SOLOS_GPIO_ATTR(PushButton, 0444, geos_gpio_show, NULL, 14); | ||
588 | static SOLOS_GPIO_ATTR(HardwareVersion, 0444, hardware_show, NULL, 0); | ||
589 | static SOLOS_GPIO_ATTR(HardwareVariant, 0444, hardware_show, NULL, 1); | ||
509 | #undef SOLOS_ATTR_RO | 590 | #undef SOLOS_ATTR_RO |
510 | #undef SOLOS_ATTR_RW | 591 | #undef SOLOS_ATTR_RW |
511 | 592 | ||
@@ -522,6 +603,23 @@ static struct attribute_group solos_attr_group = { | |||
522 | .name = "parameters", | 603 | .name = "parameters", |
523 | }; | 604 | }; |
524 | 605 | ||
606 | static struct attribute *gpio_attrs[] = { | ||
607 | &gpio_attr_GPIO1.attr.attr, | ||
608 | &gpio_attr_GPIO2.attr.attr, | ||
609 | &gpio_attr_GPIO3.attr.attr, | ||
610 | &gpio_attr_GPIO4.attr.attr, | ||
611 | &gpio_attr_GPIO5.attr.attr, | ||
612 | &gpio_attr_PushButton.attr.attr, | ||
613 | &gpio_attr_HardwareVersion.attr.attr, | ||
614 | &gpio_attr_HardwareVariant.attr.attr, | ||
615 | NULL | ||
616 | }; | ||
617 | |||
618 | static struct attribute_group gpio_attr_group = { | ||
619 | .attrs = gpio_attrs, | ||
620 | .name = "gpio", | ||
621 | }; | ||
622 | |||
525 | static int flash_upgrade(struct solos_card *card, int chip) | 623 | static int flash_upgrade(struct solos_card *card, int chip) |
526 | { | 624 | { |
527 | const struct firmware *fw; | 625 | const struct firmware *fw; |
@@ -1179,6 +1277,10 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1179 | if (err) | 1277 | if (err) |
1180 | goto out_free_irq; | 1278 | goto out_free_irq; |
1181 | 1279 | ||
1280 | if (card->fpga_version >= DMA_SUPPORTED && | ||
1281 | sysfs_create_group(&card->dev->dev.kobj, &gpio_attr_group)) | ||
1282 | dev_err(&card->dev->dev, "Could not register parameter group for GPIOs\n"); | ||
1283 | |||
1182 | return 0; | 1284 | return 0; |
1183 | 1285 | ||
1184 | out_free_irq: | 1286 | out_free_irq: |
@@ -1289,6 +1391,9 @@ static void fpga_remove(struct pci_dev *dev) | |||
1289 | iowrite32(1, card->config_regs + FPGA_MODE); | 1391 | iowrite32(1, card->config_regs + FPGA_MODE); |
1290 | (void)ioread32(card->config_regs + FPGA_MODE); | 1392 | (void)ioread32(card->config_regs + FPGA_MODE); |
1291 | 1393 | ||
1394 | if (card->fpga_version >= DMA_SUPPORTED) | ||
1395 | sysfs_remove_group(&card->dev->dev.kobj, &gpio_attr_group); | ||
1396 | |||
1292 | atm_remove(card); | 1397 | atm_remove(card); |
1293 | 1398 | ||
1294 | free_irq(dev->irq, card); | 1399 | free_irq(dev->irq, card); |