langwell_gpio: add support for whitney point
authorAlan Cox <alan@linux.intel.com>
Wed, 27 Oct 2010 22:33:23 +0000 (15:33 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Oct 2010 01:03:07 +0000 (18:03 -0700)
In this case the logic is very similar but the IRQs are not exposed and
the device is not picked up via PCI

Based on a separate internal whitney point driver by Yin Kangkai.

Signed-off-by: Alan Cox <alan@linux.intel.com>
Cc: Yin Kangkai <kangkai.yin@intel.com>
Cc: Alek Du <alek.du@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/gpio/langwell_gpio.c

index 222de1292e2b66c88a39092204f083bfe165fa3e..64db9dc3a275d94fb2cbbc39c00e8561eb8817cb 100644 (file)
 /* Supports:
  * Moorestown platform Langwell chip.
  * Medfield platform Penwell chip.
+ * Whitney point.
  */
 
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/stddef.h>
@@ -300,9 +302,88 @@ static struct pci_driver lnw_gpio_driver = {
        .probe          = lnw_gpio_probe,
 };
 
+
+static int __devinit wp_gpio_probe(struct platform_device *pdev)
+{
+       struct lnw_gpio *lnw;
+       struct gpio_chip *gc;
+       struct resource *rc;
+       int retval = 0;
+
+       rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!rc)
+               return -EINVAL;
+
+       lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL);
+       if (!lnw) {
+               dev_err(&pdev->dev,
+                       "can't allocate whitneypoint_gpio chip data\n");
+               return -ENOMEM;
+       }
+       lnw->reg_base = ioremap_nocache(rc->start, resource_size(rc));
+       if (lnw->reg_base == NULL) {
+               retval = -EINVAL;
+               goto err_kmalloc;
+       }
+       spin_lock_init(&lnw->lock);
+       gc = &lnw->chip;
+       gc->label = dev_name(&pdev->dev);
+       gc->owner = THIS_MODULE;
+       gc->direction_input = lnw_gpio_direction_input;
+       gc->direction_output = lnw_gpio_direction_output;
+       gc->get = lnw_gpio_get;
+       gc->set = lnw_gpio_set;
+       gc->to_irq = NULL;
+       gc->base = 0;
+       gc->ngpio = 64;
+       gc->can_sleep = 0;
+       retval = gpiochip_add(gc);
+       if (retval) {
+               dev_err(&pdev->dev, "whitneypoint gpiochip_add error %d\n",
+                                                               retval);
+               goto err_ioremap;
+       }
+       platform_set_drvdata(pdev, lnw);
+       return 0;
+err_ioremap:
+       iounmap(lnw->reg_base);
+err_kmalloc:
+       kfree(lnw);
+       return retval;
+}
+
+static int __devexit wp_gpio_remove(struct platform_device *pdev)
+{
+       struct lnw_gpio *lnw = platform_get_drvdata(pdev);
+       int err;
+       err = gpiochip_remove(&lnw->chip);
+       if (err)
+               dev_err(&pdev->dev, "failed to remove gpio_chip.\n");
+       iounmap(lnw->reg_base);
+       kfree(lnw);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static struct platform_driver wp_gpio_driver = {
+       .probe          = wp_gpio_probe,
+       .remove         = __devexit_p(wp_gpio_remove),
+       .driver         = {
+               .name   = "wp_gpio",
+               .owner  = THIS_MODULE,
+       },
+};
+
 static int __init lnw_gpio_init(void)
 {
-       return pci_register_driver(&lnw_gpio_driver);
+       int ret;
+       ret =  pci_register_driver(&lnw_gpio_driver);
+       if (ret < 0)
+               return ret;
+       ret = platform_driver_register(&wp_gpio_driver);
+       if (ret < 0)
+               pci_unregister_driver(&lnw_gpio_driver);
+       return ret;
 }
 
 device_initcall(lnw_gpio_init);