summaryrefslogtreecommitdiffstats
path: root/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.12-rc4/0016-efm-board-controller-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.12-rc4/0016-efm-board-controller-driver.patch')
-rw-r--r--configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.12-rc4/0016-efm-board-controller-driver.patch239
1 files changed, 239 insertions, 0 deletions
diff --git a/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.12-rc4/0016-efm-board-controller-driver.patch b/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.12-rc4/0016-efm-board-controller-driver.patch
new file mode 100644
index 0000000..3aded06
--- /dev/null
+++ b/configs/platform-energymicro-efm32gg-dk3750/patches/linux-3.12-rc4/0016-efm-board-controller-driver.patch
@@ -0,0 +1,239 @@
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
+Date: Thu, 7 Feb 2013 09:45:30 +0100
+Subject: [PATCH] efm board controller driver
+
+---
+ drivers/mfd/Kconfig | 5 ++
+ drivers/mfd/Makefile | 1 +
+ drivers/mfd/efm32board.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 200 insertions(+)
+ create mode 100644 drivers/mfd/efm32board.c
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 914c3d1..317482c 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -1065,6 +1065,11 @@ config MFD_ARIZONA_SPI
+ Support for the Wolfson Microelectronics Arizona platform audio SoC
+ core functionality controlled via I2C.
+
++config MFD_EFM32BOARD
++ tristate "efm32 board"
++ depends on ARM && (ARCH_EFM32 || COMPILE_TEST)
++ select MFD_CORE
++
+ config MFD_WM5102
+ bool "Wolfson Microelectronics WM5102"
+ depends on MFD_ARIZONA
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 15b905c..ef22ea7 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -37,6 +37,7 @@ obj-$(CONFIG_MFD_ARIZONA) += arizona-core.o
+ obj-$(CONFIG_MFD_ARIZONA) += arizona-irq.o
+ obj-$(CONFIG_MFD_ARIZONA_I2C) += arizona-i2c.o
+ obj-$(CONFIG_MFD_ARIZONA_SPI) += arizona-spi.o
++obj-$(CONFIG_MFD_EFM32BOARD) += efm32board.o
+ ifneq ($(CONFIG_MFD_WM5102),n)
+ obj-$(CONFIG_MFD_ARIZONA) += wm5102-tables.o
+ endif
+diff --git a/drivers/mfd/efm32board.c b/drivers/mfd/efm32board.c
+new file mode 100644
+index 0000000..a719985
+--- /dev/null
++++ b/drivers/mfd/efm32board.c
+@@ -0,0 +1,194 @@
++#include <linux/platform_device.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/irqdomain.h>
++#include <linux/export.h>
++#include <linux/of_gpio.h>
++#include <asm/io.h>
++
++#define DRIVER_NAME "efm32board"
++
++#define MAGIC 0x04
++#define INTFLAG 0x40
++#define INTEN 0x42
++
++struct efm32board_ddata {
++ void __iomem *base;
++ unsigned int irq;
++ struct irq_chip chip;
++ struct irq_domain *domain;
++};
++
++static void efm32board_irq_ack(struct irq_data *data)
++{
++ struct efm32board_ddata *ddata = irq_get_chip_data(data->irq);
++ unsigned short val;
++
++ /* XXX: locking */
++ val = readw(ddata->base + INTFLAG);
++ val &= ~(1 << data->hwirq);
++ writew(val, ddata->base + INTFLAG);
++}
++
++static void efm32board_irq_mask(struct irq_data *data)
++{
++ struct efm32board_ddata *ddata = irq_get_chip_data(data->irq);
++ unsigned short val;
++
++ if (data->hwirq != 2) {
++ /* XXX: locking */
++ val = readw(ddata->base + INTEN);
++ val &= ~(1 << data->hwirq);
++ writew(val, ddata->base + INTEN);
++ }
++}
++
++static void efm32board_irq_unmask(struct irq_data *data)
++{
++ struct efm32board_ddata *ddata = irq_get_chip_data(data->irq);
++ unsigned short val;
++
++ /* XXX: locking */
++ val = readw(ddata->base + INTEN);
++ val |= 1 << data->hwirq;
++ writew(val, ddata->base + INTEN);
++}
++
++static irqreturn_t efm32board_handler(int irq, void *data)
++{
++ unsigned short val;
++ struct efm32board_ddata *ddata = data;
++ irqreturn_t ret = IRQ_NONE;
++
++ val = readw(ddata->base + INTFLAG);
++ /* ack BC irq */
++ writew(0, ddata->base + INTFLAG);
++
++ pr_debug("%s: INTFLAG=%hx\n", __func__, val);
++
++ while (val) {
++ int line = __fls(val);
++
++ if (!generic_handle_irq(irq_create_mapping(ddata->domain, line)))
++ ret = IRQ_HANDLED;
++ val &= ~(1 << line);
++ }
++ return ret;
++}
++
++int efm32board_irqdomain_map(struct irq_domain *d, unsigned int virq,
++ irq_hw_number_t hw)
++{
++ struct efm32board_ddata *ddata = d->host_data;
++
++ irq_set_chip_data(virq, ddata);
++ irq_set_chip_and_handler(virq, &ddata->chip, handle_edge_irq);
++
++ set_irq_flags(virq, IRQF_VALID);
++
++ return 0;
++}
++
++const struct irq_domain_ops efm32board_irqdomain_ops = {
++ .map = efm32board_irqdomain_map,
++ .xlate = irq_domain_xlate_onecell,
++};
++
++static int efm32board_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++ int irq, gpio, ret;
++ struct efm32board_ddata *ddata;
++ unsigned short val;
++
++ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
++ if (!ddata) {
++ dev_err(&pdev->dev, "cannot allocate driver data");
++ return -ENOMEM;
++ }
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "can't get device resources\n");
++ return -ENOENT;
++ }
++
++ gpio = of_get_named_gpio_flags(pdev->dev.of_node, "irq-gpios", 0, NULL);
++ if (gpio < 0) {
++ dev_err(&pdev->dev, "can't get irq gpio\n");
++ return gpio;
++ }
++
++ ret = gpio_request(gpio, DRIVER_NAME);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot request irq gpio\n");
++ return ret;
++ }
++
++ ret = gpio_direction_input(gpio);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot configure irq gpio as input\n");
++ return ret;
++ }
++
++ irq = gpio_to_irq(gpio);
++ if (irq <= 0) {
++ dev_err(&pdev->dev, "can't get irq number\n");
++ return irq < 0 ? irq : -ENOENT;
++ }
++ ddata->irq = irq;
++
++ ddata->base = devm_request_and_ioremap(&pdev->dev, res);
++ if (!ddata->base) {
++ dev_err(&pdev->dev, "cannot request and ioremap register set\n");
++ return -EADDRNOTAVAIL;
++ }
++
++ val = readw(ddata->base + MAGIC);
++ if (val != 0xef32) {
++ dev_err(&pdev->dev, "Magic not found (0x%hx)\n", val);
++ return -ENODEV;
++ }
++
++ /* disable and clear all irqs */
++ writew(0, ddata->base + INTEN);
++ writew(0, ddata->base + INTFLAG);
++
++ /* XXX: enable joystick irq */
++ writew(4, ddata->base + INTEN);
++
++ ddata->chip.name = DRIVER_NAME;
++ ddata->chip.irq_ack = efm32board_irq_ack;
++ ddata->chip.irq_mask = efm32board_irq_mask;
++ ddata->chip.irq_unmask = efm32board_irq_unmask;
++
++ ret = request_irq(irq, efm32board_handler, 0, DRIVER_NAME, ddata);
++ if (ret)
++ goto err_request_irq;
++
++ ddata->domain = irq_domain_add_simple(pdev->dev.of_node, 5, 0,
++ &efm32board_irqdomain_ops, ddata);
++ if (!ddata->domain) {
++ ret = -ENOMEM;
++ dev_err(&pdev->dev, "cannot create irq domain\n");
++
++ free_irq(irq, ddata);
++ }
++err_request_irq:
++ return ret;
++}
++
++static const struct of_device_id efm32board_dt_ids[] = {
++ { .compatible = "efm32board", },
++ { /* sentinel */ }
++};
++
++static struct platform_driver efm32board_driver = {
++ .probe = efm32board_probe,
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .of_match_table = efm32board_dt_ids,
++ },
++};
++module_platform_driver(efm32board_driver);