summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--target/linux/realtek/files/drivers/gpio/rtl_gpio.c228
-rw-r--r--target/linux/realtek/patches-2.6.30/304-add-rtlgpio.patch28
-rw-r--r--target/linux/realtek/patches-2.6.30/305-add-gpio-driver-switching.patch25
-rw-r--r--target/linux/realtek/patches-2.6.30/306-make-gpio-rtl-honor-switch.patch11
4 files changed, 292 insertions, 0 deletions
diff --git a/target/linux/realtek/files/drivers/gpio/rtl_gpio.c b/target/linux/realtek/files/drivers/gpio/rtl_gpio.c
new file mode 100644
index 000000000..010f17f12
--- /dev/null
+++ b/target/linux/realtek/files/drivers/gpio/rtl_gpio.c
@@ -0,0 +1,228 @@
+/*
+ * RTL819X gpio driver
+ *
+ * Copyright 2012 Andrew 'Necromant' Andrianov
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ *
+ * Please note, that this driver is VERY hacky due to f*cked up nature of
+ * realtek's kernel. Say thanks to code monkeys from realtek
+ * (see arch/rlx for emailsand names) and never hire any of them ;)
+ * This driver should be properly rewritten once 3.x kernels for rlx arrive
+ * Till then it's a placeholder for a proper driver.
+ * Current Issues:
+ * * No interrupt support whatsoever.
+ * * No proper probing & platform_device defs.
+ * * Many things hardcoded. Sorry
+ *
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+/* Register Offset Definitions */
+#define RTLGPIO_CNTRL (0)
+#define RTLGPIO_DIR (2)
+#define RTLGPIO_DATA (3)
+
+/* rlx missing sizes.h ? */
+#define SZ_4K 4096
+
+#define RTL_MUX_ADDR 0xb8000040
+
+
+static int g_muxdummy;
+static uint32_t g_mux_value = 0x340FFF;
+
+static int param_set_mux(const char *val, struct kernel_param *kp)
+{
+ volatile uint32_t* mux = (uint32_t*) RTL_MUX_ADDR;
+ if (!val)
+ return -EINVAL;
+ sscanf(val, "0x%x", &g_mux_value);
+ *mux = g_mux_value;
+ printk("rtl-gpio: setting mux to 0x%x\n", g_mux_value);
+ return 0;
+}
+
+static int param_get_mux(char *buffer, struct kernel_param *kp)
+{
+ volatile uint32_t* mux = (uint32_t*) RTL_MUX_ADDR;
+ sprintf(buffer, "0x%x", *mux);
+ return strlen(buffer);
+}
+
+#define param_check_mux(a,b) ;;
+
+module_param_named(mux, g_muxdummy, mux, S_IRUGO | S_IWUSR)
+
+struct rtl_gpio_chip {
+ struct gpio_chip chip;
+ uint32_t gpio_state;
+ uint32_t gpio_dir;
+ volatile uint32_t* regs;
+ spinlock_t lock; /* Lock used for synchronization */
+};
+
+static inline struct rtl_gpio_chip *to_rtl_gpio_chip(struct gpio_chip *gc)
+{
+ return container_of(gc, struct rtl_gpio_chip, chip);
+}
+
+
+/* Dummy to make gpiolib happy */
+int gpio_to_irq(unsigned g)
+{
+ return 0;
+}
+
+EXPORT_SYMBOL(gpio_to_irq);
+
+/**
+ * rtlgpio_get - Read the specified signal of the GPIO device.
+ * @gc: Pointer to gpio_chip device structure.
+ * @gpio: GPIO signal number.
+ *
+ * This function reads the specified signal of the GPIO device. It returns 0 if
+ * the signal clear, 1 if signal is set or negative value on error.
+ */
+static int rtlgpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct rtl_gpio_chip *rgc = to_rtl_gpio_chip(gc);
+ return (*(rgc->regs + RTLGPIO_DATA) >> gpio) & 1;
+}
+
+/**
+ * rtlgpio_set - Write the specified signal of the GPIO device.
+ * @gc: Pointer to gpio_chip device structure.
+ * @gpio: GPIO signal number.
+ * @val: Value to be written to specified signal.
+ *
+ * This function writes the specified value in to the specified signal of the
+ * GPIO device.
+ */
+static void rtlgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ unsigned long flags;
+ struct rtl_gpio_chip *rgc = to_rtl_gpio_chip(gc);
+
+ spin_lock_irqsave(&rgc->lock, flags);
+ /* Write to GPIO signal and set its direction to output */
+ if (val)
+ rgc->gpio_state |= 1 << gpio;
+ else
+ rgc->gpio_state &= ~(1 << gpio);
+ *(rgc->regs + RTLGPIO_DATA) = rgc->gpio_state;
+ spin_unlock_irqrestore(&rgc->lock, flags);
+}
+
+/**
+ * rtlgpio_dir_in - Set the direction of the specified GPIO signal as input.
+ * @gc: Pointer to gpio_chip device structure.
+ * @gpio: GPIO signal number.
+ *
+ * This function sets the direction of specified GPIO signal as input.
+ * It returns 0 if direction of GPIO signals is set as input otherwise it
+ * returns negative error value.
+ */
+static int rtlgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+
+ unsigned long flags;
+ struct rtl_gpio_chip *rgc = to_rtl_gpio_chip(gc);
+
+ spin_lock_irqsave(&rgc->lock, flags);
+ /* Set the GPIO bit in shadow register and set direction as input */
+ rgc->gpio_dir &= ~(1 << gpio);
+ *(rgc->regs + RTLGPIO_DIR) = rgc->gpio_dir;
+ spin_unlock_irqrestore(&rgc->lock, flags);
+ return 0;
+}
+
+/**
+ * rtlgpio_dir_out - Set the direction of the specified GPIO signal as output.
+ * @gc: Pointer to gpio_chip device structure.
+ * @gpio: GPIO signal number.
+ * @val: Value to be written to specified signal.
+ *
+ * This function sets the direction of specified GPIO signal as output. If all
+ * GPIO signals of GPIO chip is configured as input then it returns
+ * error otherwise it returns 0.
+ */
+static int rtlgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ unsigned long flags;
+ struct rtl_gpio_chip *rgc = to_rtl_gpio_chip(gc);
+ spin_lock_irqsave(&rgc->lock, flags);
+ /* Set the GPIO bit in shadow register and set direction as input */
+ rgc->gpio_dir |= (1 << gpio);
+ *(rgc->regs + RTLGPIO_DIR) = rgc->gpio_dir;
+ spin_unlock_irqrestore(&rgc->lock, flags);
+ return 0;
+}
+
+
+static struct rtl_gpio_chip rgpio;
+static int __init rtlgpio_init(void)
+{
+/* volatile uint32_t* regs = ioremap_nocache(0xb8003500, 32);
+ volatile uint32_t* mux = ioremap_nocache(0xB8000040, 4);
+*/
+ /*
+ * Something is definetely not right here.
+ * Theory says that ioremap is the way, practice says the opposite
+ * Must be some dark realtek's magic coming from arch/rlx
+ */
+
+ volatile uint32_t* regs = (uint32_t*) 0xb8003500;
+ volatile uint32_t* mux = (uint32_t*) 0xb8000040;
+ *mux = g_mux_value;
+ printk("rtl-gpio: Hacky Realtek 819x GPIO Driver (c) Andrew 'Necromant' Andrianov 2012\n");
+ rgpio.chip.direction_input = rtlgpio_dir_in;
+ rgpio.chip.direction_output = rtlgpio_dir_out;
+ rgpio.chip.get = rtlgpio_get;
+ rgpio.chip.label = "rtl-gpio";
+ rgpio.chip.set = rtlgpio_set;
+ rgpio.chip.base = 0;
+ rgpio.chip.ngpio = 32;
+ spin_lock_init(&rgpio.lock);
+ rgpio.regs = regs;
+ rgpio.gpio_state = *(rgpio.regs + RTLGPIO_DATA);
+ rgpio.gpio_dir = *(rgpio.regs + RTLGPIO_DIR);
+ printk("rtl-gpio: remaped io regs: 0x%p, mux: 0x%p\n",
+ regs,
+ mux);
+ printk("rtl-gpio: mux:0x%x\n",
+ *mux);
+
+ printk("rtl-gpio: initial dir: 0x%x, value: 0x%x\n",
+ rgpio.gpio_state,
+ rgpio.gpio_dir);
+ gpiochip_add(&rgpio.chip);
+ return 0;
+}
+
+/* Make sure we get initialized before anyone else tries to use us */
+subsys_initcall(rtlgpio_init);
+/* No exit call at the moment as we cannot unregister of GPIO chips */
+
+
+
+MODULE_AUTHOR("Andrew 'Necromant' Andrianov");
+MODULE_DESCRIPTION("Hacky RTL819x GPIO Driver");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/realtek/patches-2.6.30/304-add-rtlgpio.patch b/target/linux/realtek/patches-2.6.30/304-add-rtlgpio.patch
new file mode 100644
index 000000000..45b62390b
--- /dev/null
+++ b/target/linux/realtek/patches-2.6.30/304-add-rtlgpio.patch
@@ -0,0 +1,28 @@
+--- a/drivers/gpio/Makefile 2012-11-05 14:07:42.074262520 +0400
++++ b/drivers/gpio/Makefile 2012-11-05 14:08:18.327603410 +0400
+@@ -10,5 +10,6 @@
+ obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
+ obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
+ obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o
+-obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o
++obj-$(CONFIG_GPIO_RTL) += rtl_gpio.o
+ obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o
++
+--- a/drivers/gpio/Kconfig 2012-11-05 14:07:47.534263615 +0400
++++ b/drivers/gpio/Kconfig 2012-11-05 14:07:58.770932541 +0400
+@@ -73,6 +73,15 @@
+ help
+ Say yes here to support the Xilinx FPGA GPIO device
+
++config GPIO_RTL
++ bool "Realtek RTL819x GPIO support"
++ help
++ Say yes here to support the Realtek GPIO found in
++ RTL819x boards. Please note, that this is a hacky
++ backport
++
++
++
+ comment "I2C GPIO expanders:"
+
+ config GPIO_MAX732X
diff --git a/target/linux/realtek/patches-2.6.30/305-add-gpio-driver-switching.patch b/target/linux/realtek/patches-2.6.30/305-add-gpio-driver-switching.patch
new file mode 100644
index 000000000..9dc6548b6
--- /dev/null
+++ b/target/linux/realtek/patches-2.6.30/305-add-gpio-driver-switching.patch
@@ -0,0 +1,25 @@
+--- linux-2.6.30.9.a/arch/rlx/Kconfig 2012-11-05 14:18:41.701066133 +0400
++++ linux-2.6.30.9.b/arch/rlx/Kconfig 2012-11-05 14:16:50.864374834 +0400
+@@ -139,6 +139,22 @@
+ config RTL_FLASH_MAPPING_ENABLE
+ bool "Enable Flash Mapping"
+
++choice
++prompt "GPIO Driver to use"
++
++config RTL_GPIO
++ bool "Use realtek's GPIO driver"
++
++
++config RTL_NGPIO
++ bool "Use Necromant's gpiolib driver (recommended)"
++ select GENERIC_GPIO
++ select ARCH_REQUIRE_GPIOLIB
++ select GPIO_RTL
++ default y
++
++endchoice
++
+ config POCKET_ROUTER_SUPPORT
+ bool "Pocket router support"
+
diff --git a/target/linux/realtek/patches-2.6.30/306-make-gpio-rtl-honor-switch.patch b/target/linux/realtek/patches-2.6.30/306-make-gpio-rtl-honor-switch.patch
new file mode 100644
index 000000000..e0c259713
--- /dev/null
+++ b/target/linux/realtek/patches-2.6.30/306-make-gpio-rtl-honor-switch.patch
@@ -0,0 +1,11 @@
+--- a/drivers/char/Makefile 2012-11-05 14:22:46.404451333 +0400
++++ b/drivers/char/Makefile 2012-11-05 14:23:57.307799712 +0400
+@@ -98,7 +98,7 @@
+ obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
+ obj-$(CONFIG_GPIO_TB0219) += tb0219.o
+ obj-$(CONFIG_TELCLOCK) += tlclk.o
+-obj-$(CONFIG_RTL_819X) += rtl_gpio.o
++obj-$(CONFIG_RTL_GPIO) += rtl_gpio.o
+ obj-$(CONFIG_RTL_NFBI_MDIO) += rtl_mdio/
+
+ obj-$(CONFIG_MWAVE) += mwave/