diff options
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/ | 
