summaryrefslogtreecommitdiffstats
path: root/target/linux/mcs814x/files-3.3/drivers/gpio/gpio-mcs814x.c
diff options
context:
space:
mode:
authorflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>2012-06-19 14:48:56 +0000
committerflorian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73>2012-06-19 14:48:56 +0000
commit7c90f3b2b498531a267b0e85c4f634f65d76eba8 (patch)
tree7b34e2be994fc0c2bdd15a6868864b39be34d6bc /target/linux/mcs814x/files-3.3/drivers/gpio/gpio-mcs814x.c
parent5fa7ed291ee18d3d7e6f24ee803ac6cfb96b625e (diff)
[mcs814x] add Moschip MSC814x support
This target currently only supports Moschip's MCS8140 SoC, but support for other chips in the same family (MCS8142, MCS8144) will be easy to add. Target support is entirely using Device Tree for probing peripherals. Drivers support include: - PCI - USB 1 & 2 - watchdog - random number generator - UART - timer - internal Ethernet PHY - Ethernet MAC core Support for the following boards is included using Device Tree - Devolo dLAN USB Extender - Tigal RBT-832 git-svn-id: svn://svn.openwrt.org/openwrt/trunk@32462 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/mcs814x/files-3.3/drivers/gpio/gpio-mcs814x.c')
-rw-r--r--target/linux/mcs814x/files-3.3/drivers/gpio/gpio-mcs814x.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/target/linux/mcs814x/files-3.3/drivers/gpio/gpio-mcs814x.c b/target/linux/mcs814x/files-3.3/drivers/gpio/gpio-mcs814x.c
new file mode 100644
index 000000000..ea53c192b
--- /dev/null
+++ b/target/linux/mcs814x/files-3.3/drivers/gpio/gpio-mcs814x.c
@@ -0,0 +1,148 @@
+/*
+ * Moschip MCS814x GPIO support
+ *
+ * Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
+ *
+ * Licensed under the GPLv2
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+struct mcs814x_gpio_chip {
+ void __iomem *regs;
+ struct gpio_chip chip;
+};
+
+#define GPIO_PIN 0x00
+#define GPIO_DIR 0x04
+
+#define to_mcs814x_gpio_chip(x) container_of(x, struct mcs814x_gpio_chip, chip)
+
+static int mcs814x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip);
+
+ return __raw_readl(mcs814x->regs + GPIO_PIN) & (1 << offset);
+}
+
+static void mcs814x_gpio_set(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip);
+ u32 mask;
+
+ mask = __raw_readl(mcs814x->regs + GPIO_PIN);
+ if (value)
+ mask |= (1 << offset);
+ else
+ mask &= ~(1 << offset);
+ __raw_writel(mask, mcs814x->regs + GPIO_PIN);
+}
+
+static int mcs814x_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip);
+ u32 mask;
+
+ mask = __raw_readl(mcs814x->regs + GPIO_DIR);
+ mask &= ~(1 << offset);
+ __raw_writel(mask, mcs814x->regs + GPIO_DIR);
+
+ return 0;
+}
+
+static int mcs814x_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ struct mcs814x_gpio_chip *mcs814x = to_mcs814x_gpio_chip(chip);
+ u32 mask;
+
+ mask = __raw_readl(mcs814x->regs + GPIO_DIR);
+ mask |= (1 << offset);
+ __raw_writel(mask, mcs814x->regs + GPIO_DIR);
+
+ return 0;
+}
+
+static int __devinit mcs814x_gpio_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct mcs814x_gpio_chip *mcs814x_chip;
+ int ret;
+ const unsigned int *num_gpios;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ num_gpios = of_get_property(pdev->dev.of_node, "num-gpios", NULL);
+ if (!num_gpios)
+ dev_err(&pdev->dev, "FIXME: no num-gpios property\n");
+
+ mcs814x_chip = kzalloc(sizeof(*mcs814x_chip), GFP_KERNEL);
+ if (!mcs814x_chip)
+ return -ENOMEM;
+
+ mcs814x_chip->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (!mcs814x_chip->regs) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ platform_set_drvdata(pdev, mcs814x_chip);
+
+#ifdef CONFIG_OF_GPIO
+ mcs814x_chip->chip.of_node = pdev->dev.of_node;
+#endif
+
+ mcs814x_chip->chip.label = pdev->name;
+ mcs814x_chip->chip.get = mcs814x_gpio_get;
+ mcs814x_chip->chip.set = mcs814x_gpio_set;
+ mcs814x_chip->chip.direction_input = mcs814x_gpio_direction_input;
+ mcs814x_chip->chip.direction_output = mcs814x_gpio_direction_output;
+ mcs814x_chip->chip.ngpio = be32_to_cpup(num_gpios);
+ /* we want dynamic base allocation */
+ mcs814x_chip->chip.base = -1;
+
+ ret = gpiochip_add(&mcs814x_chip->chip);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register gpiochip\n");
+ goto out;
+ }
+
+ return 0;
+
+out:
+ platform_set_drvdata(pdev, NULL);
+ kfree(mcs814x_chip);
+ return ret;
+}
+
+static struct of_device_id mcs814x_gpio_ids[] __devinitdata = {
+ { .compatible = "moschip,mcs814x-gpio" },
+ { /* sentinel */ },
+};
+
+static struct platform_driver mcs814x_gpio_driver = {
+ .driver = {
+ .name = "mcs814x-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = mcs814x_gpio_ids,
+ },
+ .probe = mcs814x_gpio_probe,
+};
+
+int __init mcs814x_gpio_init(void)
+{
+ return platform_driver_register(&mcs814x_gpio_driver);
+}
+postcore_initcall(mcs814x_gpio_init);